diff options
167 files changed, 2697 insertions, 1019 deletions
diff --git a/Android.bp b/Android.bp index 59530079d4ad..5af77562de85 100644 --- a/Android.bp +++ b/Android.bp @@ -474,6 +474,7 @@ java_library { "android.hardware.radio-V1.3-java", "android.hardware.radio-V1.4-java", "android.hardware.radio-V1.5-java", + "android.hardware.radio-V1.6-java", "android.hardware.thermal-V1.0-java-constants", "android.hardware.thermal-V1.0-java", "android.hardware.thermal-V1.1-java", @@ -1348,7 +1349,7 @@ droidstubs { }, libs: [ "framework-annotations-lib", - "android.hardware.radio-V1.5-java", + "android.hardware.radio-V1.6-java", ], check_api: { current: { diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp index 92dbc263cb34..c5419637dec8 100644 --- a/apct-tests/perftests/core/Android.bp +++ b/apct-tests/perftests/core/Android.bp @@ -1,3 +1,19 @@ +// +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + android_test { name: "CorePerfTests", @@ -23,17 +39,14 @@ android_test { libs: ["android.test.base"], + java_resources: [ ":GoogleFontDancingScript", ], + data: [":perfetto_artifacts"], platform_apis: true, jni_libs: ["libperftestscore_jni"], - // Use google-fonts/dancing-script for the performance metrics - // ANDROIDMK TRANSLATION ERROR: Only $(LOCAL_PATH)/.. values are allowed - // LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script - test_suites: ["device-tests"], certificate: "platform", - } diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java index 884745699789..e83c64c37678 100644 --- a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java +++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java @@ -27,6 +27,7 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.util.Preconditions; import com.android.perftests.core.R; import org.junit.Rule; @@ -73,10 +74,31 @@ public class TypefaceCreatePerfTest { final AssetManager am = context.getAssets(); while (state.keepRunning()) { - Typeface face = Typeface.createFromAsset(am, TEST_FONT_NAME); + Typeface face = createFromNonAsset(am, TEST_FONT_NAME); } } + /** + * {@link AssetManager#openNonAsset(String)} variant of + * {@link Typeface#createFromAsset(AssetManager, String)}. + */ + private static Typeface createFromNonAsset(AssetManager mgr, String path) { + Preconditions.checkNotNull(path); // for backward compatibility + Preconditions.checkNotNull(mgr); + + Typeface typeface = new Typeface.Builder(mgr, path).build(); + if (typeface != null) return typeface; + // check if the file exists, and throw an exception for backward compatibility + //noinspection EmptyTryBlock + try (InputStream inputStream = mgr.openNonAsset(path)) { + // Purposely empty + } catch (IOException e) { + throw new RuntimeException("Font asset not found " + path); + } + + return Typeface.DEFAULT; + } + @Test public void testCreate_fromFile() { BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); @@ -90,7 +112,7 @@ public class TypefaceCreatePerfTest { throw new RuntimeException(e); } - try (InputStream in = am.open(TEST_FONT_NAME); + try (InputStream in = am.openNonAsset(TEST_FONT_NAME); OutputStream out = new FileOutputStream(outFile)) { byte[] buf = new byte[1024]; int n = 0; diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index d27f5a5c006e..be8ea9ca6a4d 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -11,7 +11,7 @@ package android.app { } public class StatusBarManager { - method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean); } } diff --git a/api/system-current.txt b/api/system-current.txt index 118184df9d00..91be5bdab8b4 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11652,11 +11652,11 @@ package android.telephony.data { method public int getSuggestedRetryTime(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; - field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 2; // 0x2 - field public static final int HANDOVER_FAILURE_MODE_LEGACY = 1; // 0x1 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 3; // 0x3 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 4; // 0x4 - field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 + field public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; // 0x2 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; // 0x3 + field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; // 0xffffffff field public static final int LINK_STATUS_ACTIVE = 2; // 0x2 field public static final int LINK_STATUS_DORMANT = 1; // 0x1 field public static final int LINK_STATUS_INACTIVE = 0; // 0x0 diff --git a/api/test-current.txt b/api/test-current.txt index de67f404b696..9383152722be 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -514,7 +514,7 @@ package android.app { method public void expandNotificationsPanel(); method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean); - method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean); } public static final class StatusBarManager.DisableInfo { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 0a09801708a5..4ccc7e64308a 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3346,6 +3346,7 @@ message StyleUIChanged { optional int32 wallpaper_id_hash = 8; optional int32 color_preference = 9; optional android.stats.style.LocationPreference location_preference = 10; + optional android.stats.style.DatePreference date_preference = 11; } /** diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index cf5a7b629e38..e94fd452b7f8 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -187,16 +187,6 @@ class ContextImpl extends Context { private static final String XATTR_INODE_CODE_CACHE = "user.inode_code_cache"; /** - * Special intent extra that critical system apps can use to hide the notification for a - * foreground service. This extra should be placed in the intent passed into {@link - * #startForegroundService(Intent)}. - * - * @hide - */ - private static final String EXTRA_HIDDEN_FOREGROUND_SERVICE = - "android.intent.extra.HIDDEN_FOREGROUND_SERVICE"; - - /** * Map from package name, to preference name, to cached preferences. */ @GuardedBy("ContextImpl.class") @@ -1717,12 +1707,9 @@ class ContextImpl extends Context { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); - final boolean hideForegroundNotification = requireForeground - && service.getBooleanExtra(EXTRA_HIDDEN_FOREGROUND_SERVICE, false); ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()), requireForeground, - hideForegroundNotification, getOpPackageName(), getAttributionTag(), user.getIdentifier()); if (cn != null) { if (cn.getPackageName().equals("!")) { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index c1e6f5282b2a..95bbebecd66e 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -156,8 +156,7 @@ interface IActivityManager { boolean refContentProvider(in IBinder connection, int stableDelta, int unstableDelta); PendingIntent getRunningServiceControlPanel(in ComponentName service); ComponentName startService(in IApplicationThread caller, in Intent service, - in String resolvedType, boolean requireForeground, - boolean hideForegroundNotification, in String callingPackage, + in String resolvedType, boolean requireForeground, in String callingPackage, in String callingFeatureId, int userId); @UnsupportedAppUsage int stopService(in IApplicationThread caller, in Intent service, diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 4ff9e8d58c3a..99d21272236d 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -402,7 +402,7 @@ public class StatusBarManager { @TestApi @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.STATUS_BAR) - public void setDisabledForSimNetworkLock(boolean disabled) { + public void setExpansionDisabledForSimNetworkLock(boolean disabled) { try { final int userId = Binder.getCallingUserHandle().getIdentifier(); final IStatusBarService svc = getService(); diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index c58b5d218e74..6d22eb93fd02 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -688,6 +688,31 @@ public final class BluetoothGatt implements BluetoothProfile { } }); } + + /** + * Callback invoked when service changed event is received + * @hide + */ + @Override + public void onServiceChanged(String address) { + if (DBG) { + Log.d(TAG, "onServiceChanged() - Device=" + address); + } + + if (!address.equals(mDevice.getAddress())) { + return; + } + + runOrQueueCallback(new Runnable() { + @Override + public void run() { + final BluetoothGattCallback callback = mCallback; + if (callback != null) { + callback.onServiceChanged(BluetoothGatt.this); + } + } + }); + } }; /*package*/ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device, diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java index f718c0b57c1b..9f6b8287e791 100644 --- a/core/java/android/bluetooth/BluetoothGattCallback.java +++ b/core/java/android/bluetooth/BluetoothGattCallback.java @@ -194,4 +194,17 @@ public abstract class BluetoothGattCallback { public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout, int status) { } + + /** + * Callback indicating service changed event is received + * + * <p>Receiving this event means that the GATT database is out of sync with + * the remote device. {@link BluetoothGatt#discoverServices} should be + * called to re-discover the services. + * + * @param gatt GATT client involved + * @hide + */ + public void onServiceChanged(BluetoothGatt gatt) { + } } diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index cc4c45699bd4..a6e8c1395701 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -1245,6 +1245,7 @@ public final class Sensor { return true; case TYPE_HINGE_ANGLE: mStringType = STRING_TYPE_HINGE_ANGLE; + return true; default: return false; } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 1db544c29101..78ba7f0eec28 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -141,8 +141,8 @@ public class Build { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. diff --git a/core/java/android/os/IVibratorManagerService.aidl b/core/java/android/os/IVibratorManagerService.aidl new file mode 100644 index 000000000000..e821e3194d21 --- /dev/null +++ b/core/java/android/os/IVibratorManagerService.aidl @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2020, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.VibrationAttributes; + +/** {@hide} */ +interface IVibratorManagerService { + int[] getVibratorIds(); +} diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 40c291f14b67..91eb2a502638 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -3,6 +3,7 @@ per-file ExternalVibration.aidl = michaelwr@google.com per-file ExternalVibration.java = michaelwr@google.com per-file IExternalVibrationController.aidl = michaelwr@google.com per-file IExternalVibratorService.aidl = michaelwr@google.com +per-file IVibratorManagerService.aidl = michaelwr@google.com per-file IVibratorService.aidl = michaelwr@google.com per-file NullVibrator.java = michaelwr@google.com per-file SystemVibrator.java = michaelwr@google.com diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a7055ec0f050..07867e2a9d9b 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9708,6 +9708,14 @@ public final class Settings { public static final String DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR = "render_shadows_in_compositor"; + /** + * If true, submit buffers using blast in SurfaceView. + * (0 = false, 1 = true) + * @hide + */ + public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV = + "use_blast_adapter_sv"; + /** * Whether user has enabled development settings. */ diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 5f8b5e5dde33..c5d0a10bb108 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -458,9 +458,11 @@ public class InsetsState implements Parcelable { final ArraySet<Integer> result = new ArraySet<>(); if ((types & Type.STATUS_BARS) != 0) { result.add(ITYPE_STATUS_BAR); + result.add(ITYPE_CLIMATE_BAR); } if ((types & Type.NAVIGATION_BARS) != 0) { result.add(ITYPE_NAVIGATION_BAR); + result.add(ITYPE_EXTRA_NAVIGATION_BAR); } if ((types & Type.CAPTION_BAR) != 0) { result.add(ITYPE_CAPTION_BAR); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 8cb8e1d12d8a..5b0d950e3bd8 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo.Translator; +import android.graphics.BLASTBufferQueue; import android.graphics.Canvas; import android.graphics.ColorSpace; import android.graphics.HardwareRenderer; @@ -66,6 +67,8 @@ public class Surface implements Parcelable { private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); private static native long nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject); + private static native long nativeGetFromBlastBufferQueue(long surfaceObject, + long blastBufferQueueNativeObject); private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) throws OutOfResourcesException; @@ -534,6 +537,18 @@ public class Surface implements Parcelable { } } + private void updateNativeObject(long newNativeObject) { + synchronized (mLock) { + if (newNativeObject == mNativeObject) { + return; + } + if (mNativeObject != 0) { + nativeRelease(mNativeObject); + } + setNativeObjectLocked(newNativeObject); + } + } + /** * Copy another surface to this one. This surface now holds a reference * to the same data as the original surface, and is -not- the owner. @@ -557,16 +572,27 @@ public class Surface implements Parcelable { "null SurfaceControl native object. Are you using a released SurfaceControl?"); } long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); + updateNativeObject(newNativeObject); + } - synchronized (mLock) { - if (newNativeObject == mNativeObject) { - return; - } - if (mNativeObject != 0) { - nativeRelease(mNativeObject); - } - setNativeObjectLocked(newNativeObject); + /** + * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this + * surface's IGraphicBufferProducer. + * + * @param queue {@link BLASTBufferQueue} to copy from. + * @hide + */ + public void copyFrom(BLASTBufferQueue queue) { + if (queue == null) { + throw new IllegalArgumentException("queue must not be null"); + } + + long blastBufferQueuePtr = queue.mNativeObject; + if (blastBufferQueuePtr == 0) { + throw new NullPointerException("Null BLASTBufferQueue native object"); } + long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr); + updateNativeObject(newNativeObject); } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index abda698fdf73..a8ec9edf398d 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -23,8 +23,10 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAY import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ContentResolver; import android.content.Context; import android.content.res.CompatibilityInfo.Translator; +import android.graphics.BLASTBufferQueue; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; @@ -41,6 +43,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; +import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl.Transaction; @@ -232,6 +235,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage mSurfacePackage; + /** + * Returns {@code true} if buffers should be submitted via blast + */ + private static boolean useBlastAdapter(Context context) { + ContentResolver contentResolver = context.getContentResolver(); + return Settings.Global.getInt(contentResolver, + Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1; + } + + private final boolean mUseBlastAdapter; + private SurfaceControl mBlastSurfaceControl; + private BLASTBufferQueue mBlastBufferQueue; + public SurfaceView(Context context) { this(context, null); } @@ -252,6 +268,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes, boolean disableBackgroundLayer) { super(context, attrs, defStyleAttr, defStyleRes); + mUseBlastAdapter = useBlastAdapter(context); mRenderNode.addPositionUpdateListener(mPositionListener); setWillNotDraw(true); @@ -531,7 +548,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mRequestedVisible = false; updateSurface(); - releaseSurfaces(); + tryReleaseSurfaces(); // We don't release this as part of releaseSurfaces as // that is also called on transient visibility changes. We can't @@ -875,7 +892,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return t; } - private void releaseSurfaces() { + private void tryReleaseSurfaces() { mSurfaceAlpha = 1f; synchronized (mSurfaceControlLock) { @@ -886,18 +903,30 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } - if (mSurfaceControl != null) { - mTmpTransaction.remove(mSurfaceControl); - mSurfaceControl = null; - } - if (mBackgroundControl != null) { - mTmpTransaction.remove(mBackgroundControl); - mBackgroundControl = null; - } + releaseSurfaces(mTmpTransaction); mTmpTransaction.apply(); } } + private void releaseSurfaces(Transaction transaction) { + if (mSurfaceControl != null) { + transaction.remove(mSurfaceControl); + mSurfaceControl = null; + } + if (mBackgroundControl != null) { + transaction.remove(mBackgroundControl); + mBackgroundControl = null; + } + if (mBlastSurfaceControl != null) { + transaction.remove(mBlastSurfaceControl); + mBlastSurfaceControl = null; + } + if (mBlastBufferQueue != null) { + mBlastBufferQueue.destroy(); + mBlastBufferQueue = null; + } + } + /** @hide */ protected void updateSurface() { if (!mHaveFrame) { @@ -914,7 +943,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) { notifySurfaceDestroyed(); - releaseSurfaces(); + tryReleaseSurfaces(); return; } @@ -979,45 +1008,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); if (creating) { - mDeferredDestroySurfaceControl = mSurfaceControl; - updateOpaqueFlag(); - // SurfaceView hierarchy - // ViewRootImpl surface - // - bounds layer (crops all child surfaces to parent surface insets) - // - SurfaceView surface (drawn relative to ViewRootImpl surface) - // - Background color layer (drawn behind all SurfaceView surfaces) - // - // The bounds layer is used to crop the surface view so it does not draw into - // the parent surface inset region. Since there can be multiple surface views - // below or above the parent surface, one option is to create multiple bounds - // layer for each z order. The other option, the one implement is to create - // a single bounds layer and set z order for each child surface relative to the - // parent surface. - // When creating the surface view, we parent it to the bounds layer and then - // set the relative z order. When the parent surface changes, we have to - // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback. - final String name = "SurfaceView - " + viewRoot.getTitle().toString(); - - mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) - .setName(name) - .setLocalOwnerView(this) - .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) - .setBufferSize(mSurfaceWidth, mSurfaceHeight) - .setFormat(mFormat) - .setParent(viewRoot.getBoundsLayer()) - .setFlags(mSurfaceFlags) - .setCallsite("SurfaceView.updateSurface") - .build(); - mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) - .setName("Background for -" + name) - .setLocalOwnerView(this) - .setOpaque(true) - .setColorLayer() - .setParent(mSurfaceControl) - .setCallsite("SurfaceView.updateSurface") - .build(); - + mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot); } else if (mSurfaceControl == null) { return; } @@ -1090,8 +1082,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); if (sizeChanged && !creating) { - mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth, - mSurfaceHeight); + setBufferSize(mTmpTransaction); } mTmpTransaction.apply(); @@ -1133,19 +1124,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall notifySurfaceDestroyed(); } - if (creating) { - mSurface.copyFrom(mSurfaceControl); - } - - if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion - < Build.VERSION_CODES.O) { - // Some legacy applications use the underlying native {@link Surface} object - // as a key to whether anything has changed. In these cases, updates to the - // existing {@link Surface} will be ignored when the size changes. - // Therefore, we must explicitly recreate the {@link Surface} in these - // cases. - mSurface.createFrom(mSurfaceControl); - } + copySurface(creating /* surfaceControlCreated */, sizeChanged); if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { @@ -1189,7 +1168,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } finally { mIsCreating = false; if (mSurfaceControl != null && !mSurfaceCreated) { - releaseSurfaces(); + tryReleaseSurfaces(); } } } catch (Exception ex) { @@ -1202,6 +1181,119 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } + /** + * Copy the Surface from the SurfaceControl or the blast adapter. + * + * @param surfaceControlCreated true if we created the SurfaceControl and need to update our + * Surface if needed. + * @param bufferSizeChanged true if the BufferSize has changed and we need to recreate the + * Surface for compatibility reasons. + */ + private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) { + if (surfaceControlCreated) { + if (mUseBlastAdapter) { + mSurface.copyFrom(mBlastBufferQueue); + } else { + mSurface.copyFrom(mSurfaceControl); + } + } + + if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion + < Build.VERSION_CODES.O) { + // Some legacy applications use the underlying native {@link Surface} object + // as a key to whether anything has changed. In these cases, updates to the + // existing {@link Surface} will be ignored when the size changes. + // Therefore, we must explicitly recreate the {@link Surface} in these + // cases. + if (mUseBlastAdapter) { + mSurface.transferFrom(mBlastBufferQueue.createSurface()); + } else { + mSurface.createFrom(mSurfaceControl); + } + } + } + + private void setBufferSize(Transaction transaction) { + if (mUseBlastAdapter) { + mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, + mSurfaceHeight); + } else { + transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, + mSurfaceHeight); + } + } + + /** + * Creates the surface control hierarchy as follows + * ViewRootImpl surface + * bounds layer (crops all child surfaces to parent surface insets) + * * SurfaceView surface (drawn relative to ViewRootImpl surface) + * * Blast surface (if enabled) + * * Background color layer (drawn behind all SurfaceView surfaces) + * + * The bounds layer is used to crop the surface view so it does not draw into the parent + * surface inset region. Since there can be multiple surface views below or above the parent + * surface, one option is to create multiple bounds layer for each z order. The other option, + * the one implement is to create a single bounds layer and set z order for each child surface + * relative to the parent surface. + * When creating the surface view, we parent it to the bounds layer and then set the relative z + * order. When the parent surface changes, we have to make sure to update the relative z via + * ViewRootImpl.SurfaceChangedCallback. + * + * @return previous SurfaceControl where the content was rendered. In the surface is switched + * out, the old surface can be persevered until the new one has drawn by keeping the reference + * of the old SurfaceControl alive. + */ + private SurfaceControl createSurfaceControls(ViewRootImpl viewRoot) { + final String name = "SurfaceView - " + viewRoot.getTitle().toString(); + + SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession) + .setName(name) + .setLocalOwnerView(this) + .setParent(viewRoot.getBoundsLayer()) + .setCallsite("SurfaceView.updateSurface"); + + final SurfaceControl previousSurfaceControl; + if (mUseBlastAdapter) { + mSurfaceControl = builder + .setContainerLayer() + .build(); + previousSurfaceControl = mBlastSurfaceControl; + mBlastSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) + .setName(name + "(BLAST)") + .setLocalOwnerView(this) + .setBufferSize(mSurfaceWidth, mSurfaceHeight) + .setFormat(mFormat) + .setParent(mSurfaceControl) + .setFlags(mSurfaceFlags) + .setHidden(false) + .setBLASTLayer() + .setCallsite("SurfaceView.updateSurface") + .build(); + mBlastBufferQueue = new BLASTBufferQueue( + mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, true /* TODO */); + } else { + previousSurfaceControl = mSurfaceControl; + mSurfaceControl = builder + .setBufferSize(mSurfaceWidth, mSurfaceHeight) + .setFlags(mSurfaceFlags) + .setFormat(mFormat) + .build(); + mBlastSurfaceControl = null; + mBlastBufferQueue = null; + } + mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) + .setName("Background for " + name) + .setLocalOwnerView(this) + .setOpaque(true) + .setColorLayer() + .setParent(mSurfaceControl) + .setCallsite("SurfaceView.updateSurface") + .build(); + + return previousSurfaceControl; + } + private void onDrawFinished() { if (DEBUG) { Log.i(TAG, System.identityHashCode(this) + " " @@ -1348,16 +1440,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } - private void releaseSurfaces(Transaction t) { - if (mRtReleaseSurfaces) { - mRtReleaseSurfaces = false; - t.remove(mSurfaceControl); - t.remove(mBackgroundControl); - mSurfaceControl = null; - mBackgroundControl = null; - } - } - @Override public void positionLost(long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); @@ -1380,7 +1462,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (useBLAST) { synchronized (viewRoot.getBlastTransactionLock()) { viewRoot.getBLASTSyncTransaction().hide(mSurfaceControl); - releaseSurfaces(viewRoot.getBLASTSyncTransaction()); + if (mRtReleaseSurfaces) { + mRtReleaseSurfaces = false; + releaseSurfaces(viewRoot.getBLASTSyncTransaction()); + } } } else { if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) { @@ -1388,7 +1473,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall viewRoot.getRenderSurfaceControl(), frameNumber); } mRtTransaction.hide(mSurfaceControl); - releaseSurfaces(mRtTransaction); + if (mRtReleaseSurfaces) { + mRtReleaseSurfaces = false; + releaseSurfaces(mRtTransaction); + } // If we aren't using BLAST, we apply the transaction locally, otherwise we let // the ViewRoot apply it for us. // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to @@ -1716,7 +1804,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { - final SurfaceControl sc = p != null ? p.getSurfaceControl() : null; final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { @@ -1733,7 +1820,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage p) { initEmbeddedHierarchyForAccessibility(p); final SurfaceControl sc = p.getSurfaceControl(); - t.reparent(sc, mSurfaceControl).show(sc); + final SurfaceControl parent; + if (mUseBlastAdapter) { + parent = mBlastSurfaceControl; + } else { + parent = mSurfaceControl; + } + + t.reparent(sc, parent).show(sc); } /** @hide */ diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index d6cf0c441a86..4176e887c0e7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1810,7 +1810,7 @@ public final class ViewRootImpl implements ViewParent, mBlastSurfaceControl, width, height, mEnableTripleBuffering); // We only return the Surface the first time, as otherwise // it hasn't changed and there is no need to update. - ret = mBlastBufferQueue.getSurface(); + ret = mBlastBufferQueue.createSurface(); } else { mBlastBufferQueue.update(mBlastSurfaceControl, width, height); } @@ -2666,7 +2666,7 @@ public final class ViewRootImpl implements ViewParent, surfaceSizeChanged = true; mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y); } - final boolean alwaysConsumeSystemBarsChanged = + final boolean alwaysConsumeSystemBarsChanged = mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars; updateColorModeIfNeeded(lp.getColorMode()); surfaceCreated = !hadSurface && mSurface.isValid(); diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 4cfc205b06e9..6a07cf7bbf40 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -32,9 +32,10 @@ #include "android_os_Parcel.h" #include <binder/Parcel.h> +#include <gui/BLASTBufferQueue.h> #include <gui/Surface.h> -#include <gui/view/Surface.h> #include <gui/SurfaceControl.h> +#include <gui/view/Surface.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> @@ -300,6 +301,26 @@ static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, return reinterpret_cast<jlong>(surface.get()); } +static jlong nativeGetFromBlastBufferQueue(JNIEnv* env, jclass clazz, jlong nativeObject, + jlong blastBufferQueueNativeObj) { + Surface* self(reinterpret_cast<Surface*>(nativeObject)); + sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(blastBufferQueueNativeObj); + const sp<IGraphicBufferProducer>& bufferProducer = queue->getIGraphicBufferProducer(); + // If the underlying IGBP's are the same, we don't need to do anything. + if (self != nullptr && + IInterface::asBinder(self->getIGraphicBufferProducer()) == + IInterface::asBinder(bufferProducer)) { + return nativeObject; + } + + sp<Surface> surface(new Surface(bufferProducer, true)); + if (surface != NULL) { + surface->incStrong(&sRefBaseOwner); + } + + return reinterpret_cast<jlong>(surface.get()); +} + static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); @@ -428,38 +449,31 @@ static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jf // ---------------------------------------------------------------------------- static const JNINativeMethod gSurfaceMethods[] = { - {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", - (void*)nativeCreateFromSurfaceTexture }, - {"nativeRelease", "(J)V", - (void*)nativeRelease }, - {"nativeIsValid", "(J)Z", - (void*)nativeIsValid }, - {"nativeIsConsumerRunningBehind", "(J)Z", - (void*)nativeIsConsumerRunningBehind }, - {"nativeLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)J", - (void*)nativeLockCanvas }, - {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V", - (void*)nativeUnlockCanvasAndPost }, - {"nativeAllocateBuffers", "(J)V", - (void*)nativeAllocateBuffers }, - {"nativeCreateFromSurfaceControl", "(J)J", - (void*)nativeCreateFromSurfaceControl }, - {"nativeGetFromSurfaceControl", "(JJ)J", - (void*)nativeGetFromSurfaceControl }, - {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", - (void*)nativeReadFromParcel }, - {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", - (void*)nativeWriteToParcel }, - {"nativeGetWidth", "(J)I", (void*)nativeGetWidth }, - {"nativeGetHeight", "(J)I", (void*)nativeGetHeight }, - {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber }, - {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode }, - {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect}, - {"nativeAttachAndQueueBufferWithColorSpace", "(JLandroid/hardware/HardwareBuffer;I)I", - (void*)nativeAttachAndQueueBufferWithColorSpace}, - {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, - {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, - {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, + {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", + (void*)nativeCreateFromSurfaceTexture}, + {"nativeRelease", "(J)V", (void*)nativeRelease}, + {"nativeIsValid", "(J)Z", (void*)nativeIsValid}, + {"nativeIsConsumerRunningBehind", "(J)Z", (void*)nativeIsConsumerRunningBehind}, + {"nativeLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)J", + (void*)nativeLockCanvas}, + {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V", + (void*)nativeUnlockCanvasAndPost}, + {"nativeAllocateBuffers", "(J)V", (void*)nativeAllocateBuffers}, + {"nativeCreateFromSurfaceControl", "(J)J", (void*)nativeCreateFromSurfaceControl}, + {"nativeGetFromSurfaceControl", "(JJ)J", (void*)nativeGetFromSurfaceControl}, + {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", (void*)nativeReadFromParcel}, + {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, + {"nativeGetWidth", "(J)I", (void*)nativeGetWidth}, + {"nativeGetHeight", "(J)I", (void*)nativeGetHeight}, + {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber}, + {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode}, + {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect}, + {"nativeAttachAndQueueBufferWithColorSpace", "(JLandroid/hardware/HardwareBuffer;I)I", + (void*)nativeAttachAndQueueBufferWithColorSpace}, + {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, + {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, + {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, + {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, }; int register_android_view_Surface(JNIEnv* env) diff --git a/core/proto/android/stats/style/style_enums.proto b/core/proto/android/stats/style/style_enums.proto index f3f491ff34cd..828e4127a708 100644 --- a/core/proto/android/stats/style/style_enums.proto +++ b/core/proto/android/stats/style/style_enums.proto @@ -38,6 +38,9 @@ enum Action { LIVE_WALLPAPER_APPLIED = 16; LIVE_WALLPAPER_INFO_SELECT = 17; LIVE_WALLPAPER_CUSTOMIZE_SELECT = 18; + LIVE_WALLPAPER_QUESTIONNAIRE_SELECT = 19; + LIVE_WALLPAPER_QUESTIONNAIRE_APPLIED = 20; + LIVE_WALLPAPER_EFFECT_SHOW = 21; } enum LocationPreference { @@ -46,3 +49,9 @@ enum LocationPreference { LOCATION_CURRENT = 2; LOCATION_MANUAL = 3; } + +enum DatePreference { + DATE_PREFERENCE_UNSPECIFIED = 0; + DATE_UNAVAILABLE = 1; + DATE_MANUAL = 2; +} diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index afab7696e87d..8a000a034702 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -124,6 +124,22 @@ public class InsetsStateTest { } @Test + public void testCalculateInsets_extraNavRightClimateTop() throws Exception { + mState.getSource(ITYPE_CLIMATE_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(ITYPE_CLIMATE_BAR).setVisible(true); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, 0, 0, 0, TYPE_APPLICATION, + WINDOWING_MODE_UNDEFINED, null); + // ITYPE_CLIMATE_BAR is a type of status bar and ITYPE_EXTRA_NAVIGATION_BAR is a type + // of navigation bar. + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); + } + + @Test public void testCalculateInsets_imeIgnoredWithoutAdjustResize() { mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100)); mState.getSource(ITYPE_STATUS_BAR).setVisible(true); @@ -336,6 +352,8 @@ public class InsetsStateTest { public void testGetDefaultVisibility() { assertTrue(InsetsState.getDefaultVisibility(ITYPE_STATUS_BAR)); assertTrue(InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR)); + assertTrue(InsetsState.getDefaultVisibility(ITYPE_CLIMATE_BAR)); + assertTrue(InsetsState.getDefaultVisibility(ITYPE_EXTRA_NAVIGATION_BAR)); assertTrue(InsetsState.getDefaultVisibility(ITYPE_CAPTION_BAR)); assertFalse(InsetsState.getDefaultVisibility(ITYPE_IME)); } diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java index 5c410878c99d..92fb52837c36 100644 --- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java @@ -17,16 +17,23 @@ package android.view.inputmethod; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyInt; import android.annotation.Nullable; +import android.graphics.BlurMaskFilter; import android.os.Parcel; import android.os.UserHandle; +import android.text.Spannable; +import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.MaskFilterSpan; +import android.text.style.UnderlineSpan; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -280,6 +287,55 @@ public class EditorInfoTest { editorInfo.getInitialTextBeforeCursor(/* length= */ 60, /* flags= */ 1); } + @Test + public void testSpanAfterSurroundingTextRetrieval() { + final int flags = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE; + final SpannableStringBuilder sb = + new SpannableStringBuilder("ParcelableSpan and non-ParcelableSpan test"); + final int parcelableStart = 0; + final int parcelableEnd = 14; + final int nonParcelableStart = 19; + final int nonParcelableEnd = 37; + final UnderlineSpan parcelableSpan = new UnderlineSpan(); + final MaskFilterSpan nonParcelableSpan = + new MaskFilterSpan(new BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL)); + + // Set spans + sb.setSpan(parcelableSpan, parcelableStart, parcelableEnd, flags); + sb.setSpan(nonParcelableSpan, nonParcelableStart, nonParcelableEnd, flags); + + Object[] spansBefore = sb.getSpans(/* queryStart= */ 0, sb.length(), Object.class); + Object[] parcelableSpanBefore = sb.getSpans(parcelableStart, parcelableEnd, Object.class); + + // Verify the original spans length is 2, include ParcelableSpan and non-ParcelableSpan. + assertNotNull(spansBefore); + assertEquals(2, spansBefore.length); + + // Set initial surrounding text then retrieve the text. + EditorInfo editorInfo = new EditorInfo(); + editorInfo.initialSelStart = sb.length(); + editorInfo.initialSelEnd = sb.length(); + editorInfo.inputType = EditorInfo.TYPE_CLASS_TEXT; + editorInfo.setInitialSurroundingText(sb); + SpannableString textBeforeCursor = + (SpannableString) editorInfo.getInitialTextBeforeCursor( + /* length= */ 60, /* flags= */ 1); + + Object[] spansAfter = + textBeforeCursor.getSpans(/* queryStart= */ 0, sb.length(), Object.class); + Object[] parcelableSpanAfter = + textBeforeCursor.getSpans(parcelableStart, parcelableEnd, Object.class); + Object[] nonParcelableSpanAfter = + textBeforeCursor.getSpans(nonParcelableStart, nonParcelableEnd, Object.class); + + // Verify only remain ParcelableSpan and it's different from the original Span instance. + assertNotNull(spansAfter); + assertEquals(1, spansAfter.length); + assertEquals(1, parcelableSpanAfter.length); + assertEquals(0, nonParcelableSpanAfter.length); + assertNotEquals(parcelableSpanBefore, parcelableSpanAfter); + } + private static void assertExpectedTextLength(EditorInfo editorInfo, @Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength, @Nullable Integer expectAfterCursorLength) { diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 102c933dd84d..2779a75378b7 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -168,6 +168,7 @@ applications that come with the platform <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.LOCAL_MAC_ADDRESS"/> <permission name="android.permission.MANAGE_USERS"/> + <permission name="android.permission.MANAGE_SUBSCRIPTION_PLANS" /> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.permission.PERFORM_CDMA_PROVISIONING"/> @@ -440,6 +441,13 @@ applications that come with the platform <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/> </privapp-permissions> + <privapp-permissions package="com.android.traceur"> + <!-- Permissions required to receive BUGREPORT_STARTED intent --> + <permission name="android.permission.DUMP"/> + <!-- Permissions required for quick settings tile --> + <permission name="android.permission.STATUS_BAR"/> + </privapp-permissions> + <privapp-permissions package="com.android.tv"> <permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/> <permission name="android.permission.DVB_DEVICE"/> diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp index 3a3bea43ab86..ee5c5b0591cc 100644 --- a/data/fonts/Android.bp +++ b/data/fonts/Android.bp @@ -17,9 +17,8 @@ prebuilt_font { src: "DroidSansMono.ttf", required: [ // Roboto-Regular.ttf provides DroidSans.ttf as a symlink to itself + // Roboto-Regular.ttf provides DroidSans-Bold.ttf as a symlink to itself "Roboto-Regular.ttf", - // Roboto-Bold.ttf provides DroidSans-Bold.ttf as a symlink to itself - "Roboto-Bold.ttf", ], } diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index c992bd8f8338..0504cdc15b52 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -18,23 +18,104 @@ prefer the former when an 800 weight is requested. Since bold spans effectively add 300 to the weight, this ensures that 900 is the bold paired with the 500 weight, ensuring adequate contrast. + + TODO(rsheeter) update comment; ordering to match 800 to 900 is no longer required --> <familyset version="23"> <!-- first font is default --> <family name="sans-serif"> - <font weight="100" style="normal">Roboto-Thin.ttf</font> - <font weight="100" style="italic">Roboto-ThinItalic.ttf</font> - <font weight="300" style="normal">Roboto-Light.ttf</font> - <font weight="300" style="italic">Roboto-LightItalic.ttf</font> - <font weight="400" style="normal">Roboto-Regular.ttf</font> - <font weight="400" style="italic">Roboto-Italic.ttf</font> - <font weight="500" style="normal">Roboto-Medium.ttf</font> - <font weight="500" style="italic">Roboto-MediumItalic.ttf</font> - <font weight="900" style="normal">Roboto-Black.ttf</font> - <font weight="900" style="italic">Roboto-BlackItalic.ttf</font> - <font weight="700" style="normal">Roboto-Bold.ttf</font> - <font weight="700" style="italic">Roboto-BoldItalic.ttf</font> - </family> + <font weight="100" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="100" /> + </font> + <font weight="200" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="200" /> + </font> + <font weight="300" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="300" /> + </font> + <font weight="400" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="700" /> + </font> + <font weight="800" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="800" /> + </font> + <font weight="900" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="900" /> + </font> + <font weight="100" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="100" /> + </font> + <font weight="200" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="200" /> + </font> + <font weight="300" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="300" /> + </font> + <font weight="400" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="700" /> + </font> + <font weight="800" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="800" /> + </font> + <font weight="900" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="100" /> + <axis tag="wght" stylevalue="900" /> + </font> + </family> + <!-- Note that aliases must come after the fonts they reference. --> <alias name="sans-serif-thin" to="sans-serif" weight="100" /> @@ -47,14 +128,96 @@ <alias name="verdana" to="sans-serif" /> <family name="sans-serif-condensed"> - <font weight="300" style="normal">RobotoCondensed-Light.ttf</font> - <font weight="300" style="italic">RobotoCondensed-LightItalic.ttf</font> - <font weight="400" style="normal">RobotoCondensed-Regular.ttf</font> - <font weight="400" style="italic">RobotoCondensed-Italic.ttf</font> - <font weight="500" style="normal">RobotoCondensed-Medium.ttf</font> - <font weight="500" style="italic">RobotoCondensed-MediumItalic.ttf</font> - <font weight="700" style="normal">RobotoCondensed-Bold.ttf</font> - <font weight="700" style="italic">RobotoCondensed-BoldItalic.ttf</font> + <font weight="100" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="100" /> + </font> + <font weight="200" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="200" /> + </font> + <font weight="300" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="300" /> + </font> + <font weight="400" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="700" /> + </font> + <font weight="800" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="800" /> + </font> + <font weight="900" style="normal">Roboto-Regular.ttf + <axis tag="ital" stylevalue="0" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="900" /> + </font> + <font weight="100" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="100" /> + </font> + <font weight="200" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="200" /> + </font> + <font weight="300" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="300" /> + </font> + <font weight="400" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="400" /> + </font> + <font weight="500" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="500" /> + </font> + <font weight="600" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="600" /> + </font> + <font weight="700" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="700" /> + </font> + <font weight="800" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="800" /> + </font> + <font weight="900" style="italic">Roboto-Regular.ttf + <axis tag="ital" stylevalue="1" /> + <axis tag="wdth" stylevalue="75" /> + <axis tag="wght" stylevalue="900" /> + </font> </family> <alias name="sans-serif-condensed-light" to="sans-serif-condensed" weight="300" /> <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" /> diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 4c7e960eb0a4..4cd55e8ea210 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -24,7 +24,7 @@ import android.view.SurfaceControl; */ public final class BLASTBufferQueue { // Note: This field is accessed by native code. - private long mNativeObject; // BLASTBufferQueue* + public long mNativeObject; // BLASTBufferQueue* private static native long nativeCreate(long surfaceControl, long width, long height, boolean tripleBufferingEnabled); @@ -41,9 +41,13 @@ public final class BLASTBufferQueue { public void destroy() { nativeDestroy(mNativeObject); + mNativeObject = 0; } - public Surface getSurface() { + /** + * @return a new Surface instance from the IGraphicsBufferProducer of the adapter. + */ + public Surface createSurface() { return nativeGetSurface(mNativeObject); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java index 00146e9447bd..edbbd69ce0dc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java @@ -1319,10 +1319,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, mBackground.getRight(), mBackground.getBottom(), Op.UNION); } - void onDockedFirstAnimationFrame() { - saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget()); - } - void onDockedTopTask() { mState.animateAfterRecentsDrawn = true; startDragging(false /* animate */, false /* touching */); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java index 184342f14d4f..58106c94a000 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java @@ -68,9 +68,6 @@ public interface SplitScreen { /** Called when there's a task undocking. */ void onUndockingTask(); - /** Called when the first docked animation frame rendered. */ - void onDockedFirstAnimationFrame(); - /** Called when top task docked. */ void onDockedTopTask(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index eed5092ea96b..c8be93747f19 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -426,13 +426,6 @@ public class SplitScreenController implements SplitScreen, } } - /** Called when the first docked animation frame rendered. */ - public void onDockedFirstAnimationFrame() { - if (mView != null) { - mView.onDockedFirstAnimationFrame(); - } - } - /** Called when top task docked. */ public void onDockedTopTask() { if (mView != null) { @@ -502,6 +495,9 @@ public class SplitScreenController implements SplitScreen, mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */); updateVisibility(false /* visible */); mMinimized = false; + // Resets divider bar position to undefined, so new divider bar will apply default position + // next time entering split mode. + mDividerState.mRatioPositionBeforeMinimized = 0; removeDivider(); mImePositionProcessor.reset(); } diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 5f6b53ac767f..b8029087cb4f 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -21,6 +21,7 @@ #include <log/log.h> #include <minikin/MeasuredText.h> +#include <minikin/Measurement.h> #include "Paint.h" #include "SkPathMeasure.h" #include "Typeface.h" @@ -69,6 +70,18 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFla } } +void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, + const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out) { + minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); + + const minikin::U16StringPiece textBuf(buf, bufSize); + const minikin::StartHyphenEdit startHyphen = paint->getStartHyphenEdit(); + const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); + + minikin::getBounds(textBuf, minikin::Range(0, textBuf.size()), bidiFlags, minikinPaint, + startHyphen, endHyphen, out); +} + float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float* advances) { diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 0eacde9a467e..6cde9c553d8c 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -48,6 +48,9 @@ public: size_t contextStart, size_t contextCount, minikin::MeasuredText* mt); + static void getBounds(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, + const uint16_t* buf, size_t bufSize, minikin::MinikinRect* out); + static float measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp index d275659094be..f6c8496d84ca 100644 --- a/libs/hwui/jni/Paint.cpp +++ b/libs/hwui/jni/Paint.cpp @@ -342,18 +342,13 @@ namespace PaintGlue { } static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds, - const Paint& paint, const Typeface* typeface, jint bidiFlags) { + const Paint& paint, const Typeface* typeface, jint bidiFlagsInt) { SkRect r; SkIRect ir; - minikin::Layout layout = MinikinUtils::doLayout(&paint, - static_cast<minikin::Bidi>(bidiFlags), typeface, - text, count, // text buffer - 0, count, // draw range - 0, count, // context range - nullptr); minikin::MinikinRect rect; - layout.getBounds(&rect); + minikin::Bidi bidiFlags = static_cast<minikin::Bidi>(bidiFlagsInt); + MinikinUtils::getBounds(&paint, bidiFlags, typeface, text, count, &rect); r.fLeft = rect.mLeft; r.fTop = rect.mTop; r.fRight = rect.mRight; diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp index 1a09b1c52d8a..b5baafd3c2dc 100644 --- a/libs/hwui/tests/unit/TypefaceTests.cpp +++ b/libs/hwui/tests/unit/TypefaceTests.cpp @@ -31,10 +31,12 @@ using namespace android; namespace { -constexpr char kRobotoRegular[] = "/system/fonts/Roboto-Regular.ttf"; -constexpr char kRobotoBold[] = "/system/fonts/Roboto-Bold.ttf"; -constexpr char kRobotoItalic[] = "/system/fonts/Roboto-Italic.ttf"; -constexpr char kRobotoBoldItalic[] = "/system/fonts/Roboto-BoldItalic.ttf"; +constexpr char kRobotoVariable[] = "/system/fonts/Roboto-Regular.ttf"; + +constexpr char kRegularFont[] = "/system/fonts/NotoSerif-Regular.ttf"; +constexpr char kBoldFont[] = "/system/fonts/NotoSerif-Bold.ttf"; +constexpr char kItalicFont[] = "/system/fonts/NotoSerif-Italic.ttf"; +constexpr char kBoldItalicFont[] = "/system/fonts/NotoSerif-BoldItalic.ttf"; void unmap(const void* ptr, void* context) { void* p = const_cast<void*>(ptr); @@ -68,7 +70,7 @@ std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const ch TEST(TypefaceTest, resolveDefault_and_setDefaultTest) { std::unique_ptr<Typeface> regular(Typeface::createFromFamilies( - makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + makeSingleFamlyVector(kRobotoVariable), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get())); // Keep the original to restore it later. @@ -347,71 +349,71 @@ TEST(TypefaceTest, createFromFamilies_Single) { // In Java, new // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build(); std::unique_ptr<Typeface> regular( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false)); + Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 400, false)); EXPECT_EQ(400, regular->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, regular->fStyle.slant()); EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle); // In Java, new - // Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build(); + // Typeface.Builder("Roboto-Regular.ttf").setWeight(700).setItalic(false).build(); std::unique_ptr<Typeface> bold( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false)); + Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 700, false)); EXPECT_EQ(700, bold->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, bold->fStyle.slant()); EXPECT_EQ(Typeface::kBold, bold->fAPIStyle); // In Java, new - // Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build(); + // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(true).build(); std::unique_ptr<Typeface> italic( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true)); + Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 400, true)); EXPECT_EQ(400, italic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, italic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); // In Java, // new - // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build(); + // Typeface.Builder("Roboto-Regular.ttf").setWeight(700).setItalic(true).build(); std::unique_ptr<Typeface> boldItalic( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true)); + Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 700, true)); EXPECT_EQ(700, boldItalic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, boldItalic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); // In Java, // new - // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build(); + // Typeface.Builder("Roboto-Regular.ttf").setWeight(1100).setItalic(false).build(); std::unique_ptr<Typeface> over1000( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false)); + Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoVariable), 1100, false)); EXPECT_EQ(1000, over1000->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, over1000->fStyle.slant()); EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle); } TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) { - // In Java, new Typeface.Builder("Roboto-Regular.ttf").build(); + // In Java, new Typeface.Builder("Family-Regular.ttf").build(); std::unique_ptr<Typeface> regular(Typeface::createFromFamilies( - makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + makeSingleFamlyVector(kRegularFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(400, regular->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, regular->fStyle.slant()); EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle); - // In Java, new Typeface.Builder("Roboto-Bold.ttf").build(); + // In Java, new Typeface.Builder("Family-Bold.ttf").build(); std::unique_ptr<Typeface> bold(Typeface::createFromFamilies( - makeSingleFamlyVector(kRobotoBold), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + makeSingleFamlyVector(kBoldFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(700, bold->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::UPRIGHT, bold->fStyle.slant()); EXPECT_EQ(Typeface::kBold, bold->fAPIStyle); - // In Java, new Typeface.Builder("Roboto-Italic.ttf").build(); + // In Java, new Typeface.Builder("Family-Italic.ttf").build(); std::unique_ptr<Typeface> italic(Typeface::createFromFamilies( - makeSingleFamlyVector(kRobotoItalic), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + makeSingleFamlyVector(kItalicFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(400, italic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, italic->fStyle.slant()); EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle); - // In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build(); + // In Java, new Typeface.Builder("Family-BoldItalic.ttf").build(); std::unique_ptr<Typeface> boldItalic( - Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), + Typeface::createFromFamilies(makeSingleFamlyVector(kBoldItalicFont), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(700, boldItalic->fStyle.weight()); EXPECT_EQ(minikin::FontStyle::Slant::ITALIC, boldItalic->fStyle.slant()); @@ -420,8 +422,8 @@ TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) { TEST(TypefaceTest, createFromFamilies_Family) { std::vector<std::shared_ptr<minikin::FontFamily>> families = { - buildFamily(kRobotoRegular), buildFamily(kRobotoBold), buildFamily(kRobotoItalic), - buildFamily(kRobotoBoldItalic)}; + buildFamily(kRegularFont), buildFamily(kBoldFont), buildFamily(kItalicFont), + buildFamily(kBoldItalicFont)}; std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies( std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(400, typeface->fStyle.weight()); @@ -430,7 +432,7 @@ TEST(TypefaceTest, createFromFamilies_Family) { TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) { std::vector<std::shared_ptr<minikin::FontFamily>> families = { - buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)}; + buildFamily(kBoldFont), buildFamily(kItalicFont), buildFamily(kBoldItalicFont)}; std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies( std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); EXPECT_EQ(700, typeface->fStyle.weight()); diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java index 55bc507964e6..d3fd5c3ac061 100644 --- a/location/java/android/location/timezone/LocationTimeZoneEvent.java +++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java @@ -23,6 +23,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import com.android.internal.util.Preconditions; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -37,7 +39,7 @@ public final class LocationTimeZoneEvent implements Parcelable { @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS, EVENT_TYPE_UNCERTAIN }) - @interface EventType {} + public @interface EventType {} /** Uninitialized value for {@link #mEventType} - must not be used for real events. */ private static final int EVENT_TYPE_UNKNOWN = 0; @@ -49,8 +51,8 @@ public final class LocationTimeZoneEvent implements Parcelable { public static final int EVENT_TYPE_PERMANENT_FAILURE = 1; /** - * Indicates a successful geolocation time zone detection event. {@link #mTimeZoneIds} will be - * non-null but can legitimately be empty, e.g. for disputed areas, oceans. + * Indicates a successful geolocation time zone detection event. {@link #getTimeZoneIds()} will + * be non-null but can legitimately be empty, e.g. for disputed areas, oceans. */ public static final int EVENT_TYPE_SUCCESS = 2; @@ -81,10 +83,7 @@ public final class LocationTimeZoneEvent implements Parcelable { mTimeZoneIds = immutableList(timeZoneIds); boolean emptyTimeZoneIdListExpected = eventType != EVENT_TYPE_SUCCESS; - if (emptyTimeZoneIdListExpected && !timeZoneIds.isEmpty()) { - throw new IllegalStateException( - "timeZoneIds must only have values when eventType is success"); - } + Preconditions.checkState(!emptyTimeZoneIdListExpected || timeZoneIds.isEmpty()); mElapsedRealtimeNanos = elapsedRealtimeNanos; } @@ -102,9 +101,7 @@ public final class LocationTimeZoneEvent implements Parcelable { * * <p>This value can be reliably compared to {@link * android.os.SystemClock#elapsedRealtimeNanos}, to calculate the age of a fix and to compare - * {@link LocationTimeZoneEvent} fixes. This is reliable because elapsed real-time is guaranteed - * monotonic for each system boot and continues to increment even when the system is in deep - * sleep. + * {@link LocationTimeZoneEvent} instances. * * @return elapsed real-time of fix, in nanoseconds since system boot. */ diff --git a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java b/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java index 2a37ef882e61..5c9d2908f5df 100644 --- a/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java +++ b/location/java/com/android/internal/location/timezone/LocationTimeZoneProviderRequest.java @@ -30,7 +30,9 @@ import java.util.Objects; public final class LocationTimeZoneProviderRequest implements Parcelable { public static final LocationTimeZoneProviderRequest EMPTY_REQUEST = - new LocationTimeZoneProviderRequest(false); + new LocationTimeZoneProviderRequest( + false /* reportLocationTimeZone */, + 0 /* initializationTimeoutMillis */); public static final Creator<LocationTimeZoneProviderRequest> CREATOR = new Creator<LocationTimeZoneProviderRequest>() { @@ -45,17 +47,36 @@ public final class LocationTimeZoneProviderRequest implements Parcelable { } }; - /** Location time zone reporting is requested (true) */ private final boolean mReportLocationTimeZone; - private LocationTimeZoneProviderRequest(boolean reportLocationTimeZone) { + private final long mInitializationTimeoutMillis; + + private LocationTimeZoneProviderRequest( + boolean reportLocationTimeZone, long initializationTimeoutMillis) { mReportLocationTimeZone = reportLocationTimeZone; + mInitializationTimeoutMillis = initializationTimeoutMillis; } + /** + * Returns {@code true} if the provider should report events related to the device's current + * time zone, {@code false} otherwise. + */ public boolean getReportLocationTimeZone() { return mReportLocationTimeZone; } + // TODO(b/152744911) - once there are a couple of implementations, decide whether this needs to + // be passed to the LocationTimeZoneProvider and remove if it is not useful. + /** + * Returns the maximum time that the provider is allowed to initialize before it is expected to + * send an event of any sort. Only valid when {@link #getReportLocationTimeZone()} is {@code + * true}. Failure to send an event in this time (with some fuzz) may be interpreted as if the + * provider is uncertain of the time zone, and/or it could lead to the provider being disabled. + */ + public long getInitializationTimeoutMillis() { + return mInitializationTimeoutMillis; + } + @Override public int describeContents() { return 0; @@ -63,14 +84,15 @@ public final class LocationTimeZoneProviderRequest implements Parcelable { @Override public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(mReportLocationTimeZone ? 1 : 0); + parcel.writeBoolean(mReportLocationTimeZone); + parcel.writeLong(mInitializationTimeoutMillis); } static LocationTimeZoneProviderRequest createFromParcel(Parcel in) { - ClassLoader classLoader = LocationTimeZoneProviderRequest.class.getClassLoader(); - return new Builder() - .setReportLocationTimeZone(in.readInt() == 1) - .build(); + boolean reportLocationTimeZone = in.readBoolean(); + long initializationTimeoutMillis = in.readLong(); + return new LocationTimeZoneProviderRequest( + reportLocationTimeZone, initializationTimeoutMillis); } @Override @@ -82,31 +104,28 @@ public final class LocationTimeZoneProviderRequest implements Parcelable { return false; } LocationTimeZoneProviderRequest that = (LocationTimeZoneProviderRequest) o; - return mReportLocationTimeZone == that.mReportLocationTimeZone; + return mReportLocationTimeZone == that.mReportLocationTimeZone + && mInitializationTimeoutMillis == that.mInitializationTimeoutMillis; } @Override public int hashCode() { - return Objects.hash(mReportLocationTimeZone); + return Objects.hash(mReportLocationTimeZone, mInitializationTimeoutMillis); } @Override public String toString() { - StringBuilder s = new StringBuilder(); - s.append("TimeZoneProviderRequest["); - if (mReportLocationTimeZone) { - s.append("ON"); - } else { - s.append("OFF"); - } - s.append(']'); - return s.toString(); + return "LocationTimeZoneProviderRequest{" + + "mReportLocationTimeZone=" + mReportLocationTimeZone + + ", mInitializationTimeoutMillis=" + mInitializationTimeoutMillis + + "}"; } /** @hide */ public static final class Builder { private boolean mReportLocationTimeZone; + private long mInitializationTimeoutMillis; /** * Sets the property that enables / disables the provider. This is set to {@code false} by @@ -117,10 +136,20 @@ public final class LocationTimeZoneProviderRequest implements Parcelable { return this; } + /** + * Sets the initialization timeout. See {@link + * LocationTimeZoneProviderRequest#getInitializationTimeoutMillis()} for details. + */ + public Builder setInitializationTimeoutMillis(long timeoutMillis) { + mInitializationTimeoutMillis = timeoutMillis; + return this; + } + /** Builds the {@link LocationTimeZoneProviderRequest} instance. */ @NonNull public LocationTimeZoneProviderRequest build() { - return new LocationTimeZoneProviderRequest(this.mReportLocationTimeZone); + return new LocationTimeZoneProviderRequest( + mReportLocationTimeZone, mInitializationTimeoutMillis); } } } diff --git a/location/lib/Android.bp b/location/lib/Android.bp index cd45e8e6ffa6..c0188c0df497 100644 --- a/location/lib/Android.bp +++ b/location/lib/Android.bp @@ -20,5 +20,8 @@ java_sdk_library { libs: [ "androidx.annotation_annotation", ], - api_packages: ["com.android.location.provider"], + api_packages: [ + "com.android.location.provider", + "com.android.location.timezone.provider", + ], } diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java new file mode 100644 index 000000000000..367557442829 --- /dev/null +++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneEventUnbundled.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.timezone.provider; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.location.timezone.LocationTimeZoneEvent; +import android.os.SystemClock; +import android.os.UserHandle; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * An event from a {@link LocationTimeZoneProviderBase} sent while determining a device's time zone + * using its location. + * + * @hide + */ +public final class LocationTimeZoneEventUnbundled { + + @IntDef({ EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS, EVENT_TYPE_UNCERTAIN }) + @interface EventType {} + + /** + * Indicates there was a permanent failure. This is not generally expected, and probably means a + * required backend service has been turned down, or the client is unreasonably old. + */ + public static final int EVENT_TYPE_PERMANENT_FAILURE = + LocationTimeZoneEvent.EVENT_TYPE_PERMANENT_FAILURE; + + /** + * Indicates a successful geolocation time zone detection event. {@link #getTimeZoneIds()} will + * be non-null but can legitimately be empty, e.g. for disputed areas, oceans. + */ + public static final int EVENT_TYPE_SUCCESS = LocationTimeZoneEvent.EVENT_TYPE_SUCCESS; + + /** + * Indicates the time zone is not known because of an expected runtime state or error, e.g. when + * the provider is unable to detect location, or there was a problem when resolving the location + * to a time zone. + */ + public static final int EVENT_TYPE_UNCERTAIN = LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN; + + @NonNull + private final LocationTimeZoneEvent mDelegate; + + private LocationTimeZoneEventUnbundled(@NonNull LocationTimeZoneEvent delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the event type. + */ + @Nullable + public @EventType int getEventType() { + return mDelegate.getEventType(); + } + + /** + * Gets the time zone IDs of this event. Contains zero or more IDs for a successful lookup. + * The value is undefined for an unsuccessful lookup. See also {@link #getEventType()}. + */ + @NonNull + public List<String> getTimeZoneIds() { + return mDelegate.getTimeZoneIds(); + } + + /** + * Returns the information from this as a {@link LocationTimeZoneEvent}. + * @hide + */ + @NonNull + public LocationTimeZoneEvent getInternalLocationTimeZoneEvent() { + return mDelegate; + } + + @Override + public String toString() { + return "LocationTimeZoneEventUnbundled{" + + "mDelegate=" + mDelegate + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LocationTimeZoneEventUnbundled that = (LocationTimeZoneEventUnbundled) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return mDelegate.hashCode(); + } + + /** + * A builder of {@link LocationTimeZoneEventUnbundled} instances. + * + * @hide + */ + public static final class Builder { + + private @EventType int mEventType; + private @NonNull List<String> mTimeZoneIds = Collections.emptyList(); + + /** + * Set the time zone ID of this event. + */ + @NonNull + public Builder setEventType(@EventType int eventType) { + checkValidEventType(eventType); + mEventType = eventType; + return this; + } + + /** + * Sets the time zone IDs of this event. + */ + @NonNull + public Builder setTimeZoneIds(@NonNull List<String> timeZoneIds) { + mTimeZoneIds = Objects.requireNonNull(timeZoneIds); + return this; + } + + /** + * Builds a {@link LocationTimeZoneEventUnbundled} instance. + */ + @NonNull + public LocationTimeZoneEventUnbundled build() { + final int internalEventType = this.mEventType; + LocationTimeZoneEvent event = new LocationTimeZoneEvent.Builder() + .setUserHandle(UserHandle.of(ActivityManager.getCurrentUser())) + .setEventType(internalEventType) + .setTimeZoneIds(mTimeZoneIds) + .setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()) + .build(); + return new LocationTimeZoneEventUnbundled(event); + } + } + + private static int checkValidEventType(int eventType) { + if (eventType != EVENT_TYPE_SUCCESS + && eventType != EVENT_TYPE_UNCERTAIN + && eventType != EVENT_TYPE_PERMANENT_FAILURE) { + throw new IllegalStateException("eventType=" + eventType); + } + return eventType; + } +} diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java index c533c20d07e3..9df71664ee1b 100644 --- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java +++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderBase.java @@ -18,7 +18,6 @@ package com.android.location.timezone.provider; import android.annotation.Nullable; import android.content.Context; -import android.location.timezone.LocationTimeZoneEvent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; @@ -30,12 +29,34 @@ import com.android.internal.location.timezone.LocationTimeZoneProviderRequest; import java.util.Objects; /** - * Base class for location time zone providers implemented as unbundled services. + * A base class for location time zone providers implemented as unbundled services. * - * TODO(b/152744911): Provide details of the expected service actions and threading. + * <p>Provider implementations are enabled / disabled via a call to {@link + * #onSetRequest(LocationTimeZoneProviderRequestUnbundled)}. + * + * <p>Once enabled, providers are expected to detect the time zone if possible, and report the + * result via {@link #reportLocationTimeZoneEvent(LocationTimeZoneEventUnbundled)} with a type of + * either {@link LocationTimeZoneEventUnbundled#EVENT_TYPE_UNCERTAIN} or {@link + * LocationTimeZoneEventUnbundled#EVENT_TYPE_SUCCESS}. Providers may also report that they have + * permanently failed by sending an event of type {@link + * LocationTimeZoneEventUnbundled#EVENT_TYPE_PERMANENT_FAILURE}. See the javadocs for each event + * type for details. + * + * <p>Providers are expected to issue their first event within {@link + * LocationTimeZoneProviderRequest#getInitializationTimeoutMillis()}. + * + * <p>Once disabled or have failed, providers are required to stop producing events. + * + * <p>Threading: + * + * <p>Calls to {@link #reportLocationTimeZoneEvent(LocationTimeZoneEventUnbundled)} can be made on + * on any thread, but may be processed asynchronously by the system server. Similarly, calls to + * {@link #onSetRequest(LocationTimeZoneProviderRequestUnbundled)} may occur on any thread. * * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain * API stable. + * + * @hide */ public abstract class LocationTimeZoneProviderBase { @@ -64,11 +85,11 @@ public abstract class LocationTimeZoneProviderBase { /** * Reports a new location time zone event from this provider. */ - public void reportLocationTimeZoneEvent(LocationTimeZoneEvent locationTimeZoneEvent) { + protected void reportLocationTimeZoneEvent(LocationTimeZoneEventUnbundled event) { ILocationTimeZoneProviderManager manager = mManager; if (manager != null) { try { - manager.onLocationTimeZoneEvent(locationTimeZoneEvent); + manager.onLocationTimeZoneEvent(event.getInternalLocationTimeZoneEvent()); } catch (RemoteException | RuntimeException e) { Log.w(mTag, e); } diff --git a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java index e898bbf3ecc0..ab50dc3b00fc 100644 --- a/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java +++ b/location/lib/java/com/android/location/timezone/provider/LocationTimeZoneProviderRequestUnbundled.java @@ -34,15 +34,30 @@ public final class LocationTimeZoneProviderRequestUnbundled { private final LocationTimeZoneProviderRequest mRequest; + /** @hide */ public LocationTimeZoneProviderRequestUnbundled( @NonNull LocationTimeZoneProviderRequest request) { mRequest = Objects.requireNonNull(request); } + /** + * Returns {@code true} if the provider should report events related to the device's current + * time zone, {@code false} otherwise. + */ public boolean getReportLocationTimeZone() { return mRequest.getReportLocationTimeZone(); } + /** + * Returns the maximum time that the provider is allowed to initialize before it is expected to + * send an event of any sort. Only valid when {@link #getReportLocationTimeZone()} is {@code + * true}. Failure to send an event in this time (with some fuzz) may be interpreted as if the + * provider is uncertain of the time zone, and/or it could lead to the provider being disabled. + */ + public long getInitializationTimeoutMillis() { + return mRequest.getInitializationTimeoutMillis(); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java index 21376bb0fecb..8cbe52f7c481 100644 --- a/media/java/android/media/MediaTranscodeManager.java +++ b/media/java/android/media/MediaTranscodeManager.java @@ -462,9 +462,7 @@ public final class MediaTranscodeManager { mTranscodingClient = service.registerClient( mTranscodingClientCallback, mPackageName, - mPackageName, - IMediaTranscodingService.USE_CALLING_UID, - IMediaTranscodingService.USE_CALLING_PID); + mPackageName); if (mTranscodingClient != null) { mTranscodingClient.asBinder().linkToDeath(() -> onClientDied(), /* flags */ 0); diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index 85136df0d1ad..6c0dd3394cd7 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -11,7 +11,7 @@ package android.app { } public class StatusBarManager { - method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean); } } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index e27ca09f8e86..746f8aae7122 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -10514,11 +10514,11 @@ package android.telephony.data { method public int getSuggestedRetryTime(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; - field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 2; // 0x2 - field public static final int HANDOVER_FAILURE_MODE_LEGACY = 1; // 0x1 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 3; // 0x3 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 4; // 0x4 - field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 + field public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; // 0x2 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; // 0x3 + field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; // 0xffffffff field public static final int LINK_STATUS_ACTIVE = 2; // 0x2 field public static final int LINK_STATUS_DORMANT = 1; // 0x1 field public static final int LINK_STATUS_INACTIVE = 0; // 0x0 diff --git a/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml b/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml new file mode 100644 index 000000000000..1b12eb404d5e --- /dev/null +++ b/packages/CarSystemUI/res/drawable/system_bar_background_pill.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/system_bar_background_pill_color"/> + <corners android:radius="30dp"/> +</shape>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml index b07dde582e5f..8314ba5600a9 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml @@ -30,22 +30,13 @@ android:layout_height="wrap_content" android:layoutDirection="ltr"> - <com.android.systemui.car.navigationbar.CarNavigationButton + <com.android.systemui.car.hvac.AdjustableTemperatureView + android:id="@+id/driver_hvac" android:layout_width="wrap_content" android:layout_height="match_parent" - android:layout_alignParentStart="true" - android:background="@null" - systemui:broadcast="true" - systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"> - - <com.android.systemui.car.hvac.AdjustableTemperatureView - android:id="@+id/driver_hvac" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - systemui:hvacAreaId="49" - systemui:hvacTempFormat="%.0f\u00B0" /> - </com.android.systemui.car.navigationbar.CarNavigationButton> + android:gravity="center_vertical" + systemui:hvacAreaId="49" + systemui:hvacTempFormat="%.0f\u00B0" /> <LinearLayout android:layout_width="wrap_content" @@ -66,69 +57,55 @@ android:id="@+id/home" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" + systemui:highlightWhenSelected="true" systemui:icon="@drawable/car_ic_home" - systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end" - systemui:selectedIcon="@drawable/car_ic_home_selected"/> + systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end"/> <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/phone_nav" style="@style/NavigationBarButton" + systemui:highlightWhenSelected="true" systemui:icon="@drawable/car_ic_phone" systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;package=com.android.car.dialer;launchFlags=0x10000000;end" - systemui:packages="com.android.car.dialer" - systemui:selectedIcon="@drawable/car_ic_phone_selected"/> + systemui:packages="com.android.car.dialer"/> <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/grid_nav" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.AppGridActivity" + systemui:highlightWhenSelected="true" systemui:icon="@drawable/car_ic_apps" - systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end" - systemui:selectedIcon="@drawable/car_ic_apps_selected"/> + systemui:intent="intent:#Intent;component=com.android.car.carlauncher/.AppGridActivity;launchFlags=0x24000000;end"/> <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/hvac" style="@style/NavigationBarButton" + systemui:highlightWhenSelected="true" systemui:icon="@drawable/car_ic_hvac" systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end" - systemui:selectedIcon="@drawable/car_ic_hvac_selected" systemui:broadcast="true"/> <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/notifications" style="@style/NavigationBarButton" + systemui:highlightWhenSelected="true" systemui:icon="@drawable/car_ic_notification" systemui:longIntent="intent:#Intent;component=com.android.car.bugreport/.BugReportActivity;end"/> - <com.android.systemui.car.navigationbar.AssitantButton - android:id="@+id/assist" - style="@style/NavigationBarButton" - systemui:icon="@drawable/ic_mic_white" - systemui:useDefaultAppIconForRole="true"/> - <Space android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> </LinearLayout> - <com.android.systemui.car.navigationbar.CarNavigationButton + <com.android.systemui.car.hvac.AdjustableTemperatureView + android:id="@+id/passenger_hvac" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentEnd="true" - android:background="@null" - systemui:broadcast="true" - systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"> - - <com.android.systemui.car.hvac.AdjustableTemperatureView - android:id="@+id/passenger_hvac" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_alignParentEnd="true" - android:gravity="center_vertical" - systemui:hvacAreaId="68" - systemui:hvacTempFormat="%.0f\u00B0" /> - </com.android.systemui.car.navigationbar.CarNavigationButton> + android:gravity="center_vertical" + systemui:hvacAreaId="68" + systemui:hvacTempFormat="%.0f\u00B0" /> </RelativeLayout> <LinearLayout diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml index a8f115742023..9f79023b0f31 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_button.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml @@ -36,7 +36,7 @@ android:background="@android:color/transparent" android:scaleType="fitCenter" android:tintMode="src_in" - android:tint="@color/car_nav_icon_fill_color" + android:tint="@color/car_nav_icon_fill_color_selected" android:clickable="false" /> diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml index af8482a8c6a5..07c11c76a4f2 100644 --- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml +++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml @@ -31,43 +31,30 @@ android:layoutDirection="ltr"> <FrameLayout - android:id="@+id/user_name_container" + android:id="@+id/system_icon_area" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentStart="true" - android:layout_toStartOf="@+id/clock_container" + android:layout_marginTop="@dimen/car_padding_2" + android:layout_centerVertical="true" + android:gravity="center_vertical" > - <com.android.systemui.car.navigationbar.CarNavigationButton - android:id="@+id/user_name" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="match_parent" - systemui:icon="@null" - systemui:intent="intent:#Intent;component=com.android.car.settings/.users.UserSwitcherActivity;launchFlags=0x24000000;end" - > - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="horizontal" + android:background="@drawable/system_bar_background_pill" + android:layout_weight="1" + android:layout_marginStart="@dimen/car_padding_2" + android:gravity="center_vertical" + systemui:intent="intent:#Intent;component=com.android.car.settings/.common.CarSettingActivities$QuickSettingActivity;launchFlags=0x24000000;end"> + + <include + layout="@layout/system_icons" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" android:gravity="center_vertical" - > - <ImageView - android:id="@+id/user_avatar" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:src="@drawable/car_ic_user_icon" - android:paddingLeft="@dimen/system_bar_user_icon_padding" - android:paddingRight="@dimen/system_bar_user_icon_padding" - /> - <TextView - android:id="@+id/user_name_text" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:gravity="center_vertical" - android:textAppearance="@style/TextAppearance.SystemBar.Username" - android:maxLines="1" - /> - </LinearLayout> + /> </com.android.systemui.car.navigationbar.CarNavigationButton> </FrameLayout> @@ -96,25 +83,51 @@ /> </FrameLayout> - <LinearLayout - android:id="@+id/system_icon_area" + <FrameLayout + android:id="@+id/user_name_container" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentEnd="true" android:layout_centerVertical="true" - android:paddingEnd="@*android:dimen/car_padding_1" - android:gravity="center_vertical" - android:orientation="horizontal" + android:layout_marginTop="@dimen/car_padding_2" > - - <include - layout="@layout/system_icons" + <com.android.systemui.car.navigationbar.CarNavigationButton + android:id="@+id/user_name" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" + android:layout_height="match_parent" + android:layout_marginEnd="@dimen/car_padding_2" + android:background="@drawable/system_bar_background_pill" android:gravity="center_vertical" - /> - </LinearLayout> + systemui:intent="intent:#Intent;component=com.android.car.settings/.users.UserSwitcherActivity;launchFlags=0x24000000;end" + > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:layout_marginStart="@dimen/car_padding_2" + android:layout_marginEnd="@dimen/car_padding_2" + android:gravity="center_vertical" + > + <ImageView + android:id="@+id/user_avatar" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:src="@drawable/car_ic_user_icon" + android:layout_marginEnd="@dimen/system_bar_user_icon_padding" + /> + <TextView + android:id="@+id/user_name_text" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:gravity="center_vertical" + android:textAppearance="@style/TextAppearance.SystemBar.Username" + android:maxLines="1" + android:maxLength="10" + android:layout_marginEnd="@dimen/system_bar_user_icon_padding" + /> + </LinearLayout> + </com.android.systemui.car.navigationbar.CarNavigationButton> + </FrameLayout> </RelativeLayout> </com.android.systemui.car.navigationbar.CarNavigationBarView> diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml index d23579294ce8..5c06075e8617 100644 --- a/packages/CarSystemUI/res/layout/system_icons.xml +++ b/packages/CarSystemUI/res/layout/system_icons.xml @@ -24,10 +24,11 @@ <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons" - android:layout_width="0dp" + android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" - android:paddingEnd="4dp" + android:padding="10dp" + android:scaleType="fitCenter" android:gravity="center_vertical" android:orientation="horizontal" /> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index c390cc8d70a4..6fe5004c459f 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -32,8 +32,9 @@ <color name="system_bar_background_opaque">#ff172026</color> <!-- colors for status bar --> - <color name="system_bar_user_icon_color">#ffffff</color> - <color name="system_bar_text_color">#ffffff</color> + <color name="system_bar_background_pill_color">#282A2D</color> + <color name="system_bar_user_icon_color">#FFFFFF</color> + <color name="system_bar_text_color">#FFFFFF</color> <color name="status_bar_background_color">#33000000</color> <drawable name="system_bar_background">@color/status_bar_background_color</drawable> diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java index e7e33a5439f9..d2b931b3624b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java @@ -96,11 +96,11 @@ public class CarNavigationButton extends LinearLayout { public void setSelected(boolean selected) { super.setSelected(selected); mSelected = selected; + if (mHighlightWhenSelected) { - // Always apply selected alpha if the button does not toggle alpha based on selection - // state. - setAlpha(!mHighlightWhenSelected || mSelected ? mSelectedAlpha : mUnselectedAlpha); + setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha); } + if (mShowMoreWhenSelected && mMoreIcon != null) { mMoreIcon.setVisibility(selected ? VISIBLE : GONE); } @@ -299,10 +299,10 @@ public class CarNavigationButton extends LinearLayout { mIsDefaultAppIconForRoleEnabled = typedArray.getBoolean( R.styleable.CarNavigationButton_useDefaultAppIconForRole, false); mIcon = findViewById(R.id.car_nav_button_icon_image); - // Always apply selected alpha if the button does not toggle alpha based on selection state. - mIcon.setAlpha(mHighlightWhenSelected ? mUnselectedAlpha : mSelectedAlpha); + // Always apply un-selected alpha regardless of if the button toggles alpha based on + // selection state. + setAlpha(mHighlightWhenSelected ? mUnselectedAlpha : mSelectedAlpha); mMoreIcon = findViewById(R.id.car_nav_button_more_icon); - mMoreIcon.setAlpha(mSelectedAlpha); mUnseenIcon = findViewById(R.id.car_nav_button_unseen_icon); updateImage(); } diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 91510f65316f..9788b30f82c4 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -228,6 +228,7 @@ public class SettingsBackupTest { Settings.Global.DEVELOPMENT_FORCE_RTL, Settings.Global.DEVELOPMENT_ENABLE_SIZECOMPAT_FREEFORM, Settings.Global.DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, + Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, Settings.Global.DEVICE_DEMO_MODE, Settings.Global.BATTERY_SAVER_ADAPTIVE_CONSTANTS, Settings.Global.BATTERY_SAVER_CONSTANTS, diff --git a/packages/SystemUI/res/values-h740dp-port/dimens.xml b/packages/SystemUI/res/values-h740dp-port/dimens.xml new file mode 100644 index 000000000000..966066ffe56b --- /dev/null +++ b/packages/SystemUI/res/values-h740dp-port/dimens.xml @@ -0,0 +1,27 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<resources> + <dimen name="qs_tile_height">106dp</dimen> + <dimen name="qs_tile_margin_vertical">24dp</dimen> + + <!-- The height of the qs customize header. Should be + (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) - + (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp)) + --> + <dimen name="qs_customize_header_min_height">46dp</dimen> + <dimen name="qs_tile_margin_top">18dp</dimen> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d5362baaacf0..48da5d90efe0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -484,20 +484,20 @@ <!-- The size of the gesture span needed to activate the "pull" notification expansion --> <dimen name="pull_span_min">25dp</dimen> - <dimen name="qs_tile_height">106dp</dimen> + <dimen name="qs_tile_height">96dp</dimen> <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 --> <dimen name="qs_tile_layout_margin_side">18dp</dimen> <dimen name="qs_tile_margin_horizontal">18dp</dimen> <dimen name="qs_tile_margin_horizontal_two_line">2dp</dimen> - <dimen name="qs_tile_margin_vertical">24dp</dimen> + <dimen name="qs_tile_margin_vertical">2dp</dimen> <dimen name="qs_tile_margin_top_bottom">12dp</dimen> <dimen name="qs_tile_margin_top_bottom_negative">-12dp</dimen> <!-- The height of the qs customize header. Should be - (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (18dp)) - + (qs_panel_padding_top (48dp) + brightness_mirror_height (48dp) + qs_tile_margin_top (0dp)) - (Toolbar_minWidth (56dp) + qs_tile_margin_top_bottom (12dp)) --> - <dimen name="qs_customize_header_min_height">46dp</dimen> - <dimen name="qs_tile_margin_top">18dp</dimen> + <dimen name="qs_customize_header_min_height">28dp</dimen> + <dimen name="qs_tile_margin_top">0dp</dimen> <dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen> <dimen name="qs_tile_background_size">44dp</dimen> <dimen name="qs_quick_tile_size">48dp</dimen> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 8ed79290c8d4..c94bcaaf7383 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -44,11 +44,6 @@ interface ISystemUiProxy { void startScreenPinning(int taskId) = 1; /** - * Notifies SystemUI that split screen has been invoked. - */ - void onSplitScreenInvoked() = 5; - - /** * Notifies SystemUI that Overview is shown. */ void onOverviewShown(boolean fromHome) = 6; diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 832edf719dbb..f24644bfe312 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -37,7 +37,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.appops.AppOpsController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; @@ -126,6 +126,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.SystemWindows; +import java.util.concurrent.Executor; import java.util.function.Consumer; import javax.inject.Inject; @@ -167,6 +168,15 @@ public class Dependency { * Generic handler on the main thread. */ private static final String MAIN_HANDLER_NAME = "main_handler"; + /** + * Generic executor on the main thread. + */ + private static final String MAIN_EXECUTOR_NAME = "main_executor"; + + /** + * Generic executor on a background thread. + */ + private static final String BACKGROUND_EXECUTOR_NAME = "background_executor"; /** * An email address to send memory leak reports to by default. @@ -199,6 +209,17 @@ public class Dependency { new DependencyKey<>(MAIN_HANDLER_NAME); /** + * Generic executor on the main thread. + */ + public static final DependencyKey<Executor> MAIN_EXECUTOR = + new DependencyKey<>(MAIN_EXECUTOR_NAME); + /** + * Generic executor on a background thread. + */ + public static final DependencyKey<Executor> BACKGROUND_EXECUTOR = + new DependencyKey<>(BACKGROUND_EXECUTOR_NAME); + + /** * An email address to send memory leak reports to by default. */ public static final DependencyKey<String> LEAK_REPORT_EMAIL = @@ -288,7 +309,7 @@ public class Dependency { @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil; @Inject Lazy<SmartReplyController> mSmartReplyController; @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler; - @Inject Lazy<BubbleController> mBubbleController; + @Inject Lazy<Bubbles> mBubbles; @Inject Lazy<NotificationEntryManager> mNotificationEntryManager; @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager; @Inject Lazy<AutoHideController> mAutoHideController; @@ -301,6 +322,8 @@ public class Dependency { @Inject @Named(TIME_TICK_HANDLER_NAME) Lazy<Handler> mTimeTickHandler; @Nullable @Inject @Named(LEAK_REPORT_EMAIL_NAME) Lazy<String> mLeakReportEmail; + @Inject @Main Lazy<Executor> mMainExecutor; + @Inject @Background Lazy<Executor> mBackgroundExecutor; @Inject Lazy<ClockManager> mClockManager; @Inject Lazy<ActivityManagerWrapper> mActivityManagerWrapper; @Inject Lazy<DevicePolicyManagerWrapper> mDevicePolicyManagerWrapper; @@ -336,6 +359,8 @@ public class Dependency { mProviders.put(BG_LOOPER, mBgLooper::get); mProviders.put(MAIN_LOOPER, mMainLooper::get); mProviders.put(MAIN_HANDLER, mMainHandler::get); + mProviders.put(MAIN_EXECUTOR, mMainExecutor::get); + mProviders.put(BACKGROUND_EXECUTOR, mBackgroundExecutor::get); mProviders.put(ActivityStarter.class, mActivityStarter::get); mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get); @@ -483,7 +508,7 @@ public class Dependency { mProviders.put(SmartReplyController.class, mSmartReplyController::get); mProviders.put(RemoteInputQuickSettingsDisabler.class, mRemoteInputQuickSettingsDisabler::get); - mProviders.put(BubbleController.class, mBubbleController::get); + mProviders.put(Bubbles.class, mBubbles::get); mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get); mProviders.put(ForegroundServiceNotificationListener.class, mForegroundServiceNotificationListener::get); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index fbb47e2086b3..5b852086fe9f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -294,6 +294,15 @@ class Bubble implements BubbleViewProvider { } /** + * Sets whether this bubble is considered visually interruptive. Normally pulled from the + * {@link NotificationEntry}, this method is purely for testing. + */ + @VisibleForTesting + void setVisuallyInterruptiveForTest(boolean visuallyInterruptive) { + mIsVisuallyInterruptive = visuallyInterruptive; + } + + /** * Starts a task to inflate & load any necessary information to display a bubble. * * @param callback the callback to notify one the bubble is ready to be displayed. @@ -419,6 +428,7 @@ class Bubble implements BubbleViewProvider { } else if (mIntent != null && entry.getBubbleMetadata().getIntent() == null) { // Was an intent bubble now it's a shortcut bubble... still unregister the listener mIntent.unregisterCancelListener(mIntentCancelListener); + mIntentActive = false; mIntent = null; } mDeleteIntent = entry.getBubbleMetadata().getDeleteIntent(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 90b1f55ac514..dff405cb162c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -129,7 +129,8 @@ import java.util.Objects; * * The controller manages addition, removal, and visible state of bubbles on screen. */ -public class BubbleController implements ConfigurationController.ConfigurationListener, Dumpable { +public class BubbleController implements Bubbles, ConfigurationController.ConfigurationListener, + Dumpable { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES; @@ -414,7 +415,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (bubble.getBubbleIntent() == null) { return; } - if (bubble.isIntentActive()) { + if (bubble.isIntentActive() + || mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { bubble.setPendingIntentCanceled(); return; } @@ -519,6 +521,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi /** * See {@link NotifCallback}. */ + @Override public void addNotifCallback(NotifCallback callback) { mCallbacks.add(callback); } @@ -700,6 +703,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * since we want the scrim's appearance and behavior to be identical to that of the notification * shade scrim. */ + @Override public ScrimView getScrimForBubble() { return mBubbleScrim; } @@ -708,6 +712,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * Called when the status bar has become visible or invisible (either permanently or * temporarily). */ + @Override public void onStatusBarVisibilityChanged(boolean visible) { if (mStackView != null) { // Hide the stack temporarily if the status bar has been made invisible, and the stack @@ -725,14 +730,16 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mInflateSynchronously = inflateSynchronously; } - void setOverflowListener(BubbleData.Listener listener) { + @Override + public void setOverflowListener(BubbleData.Listener listener) { mOverflowListener = listener; } /** * @return Bubbles for updating overflow. */ - List<Bubble> getOverflowBubbles() { + @Override + public List<Bubble> getOverflowBubbles() { return mBubbleData.getOverflowBubbles(); } @@ -955,13 +962,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - boolean inLandscape() { - return mOrientation == Configuration.ORIENTATION_LANDSCAPE; - } - /** * Set a listener to be notified of bubble expand events. */ + @Override public void setExpandListener(BubbleExpandListener listener) { mExpandListener = ((isExpanding, key) -> { if (listener != null) { @@ -987,29 +991,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi return mBubbleData.hasBubbles(); } - /** - * Whether the stack of bubbles is expanded or not. - */ + @Override public boolean isStackExpanded() { return mBubbleData.isExpanded(); } - /** - * Tell the stack of bubbles to collapse. - */ + @Override public void collapseStack() { mBubbleData.setExpanded(false /* expanded */); } - /** - * True if either: - * (1) There is a bubble associated with the provided key and if its notification is hidden - * from the shade. - * (2) There is a group summary associated with the provided key that is hidden from the shade - * because it has been dismissed but still has child bubbles active. - * - * False otherwise. - */ + @Override public boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry) { String key = entry.getKey(); boolean isSuppressedBubble = (mBubbleData.hasAnyBubbleWithKey(key) @@ -1021,19 +1013,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi return (isSummary && isSuppressedSummary) || isSuppressedBubble; } - /** - * True if: - * (1) The current notification entry same as selected bubble notification entry and the - * stack is currently expanded. - * - * False otherwise. - */ + @Override public boolean isBubbleExpanded(NotificationEntry entry) { return isStackExpanded() && mBubbleData != null && mBubbleData.getSelectedBubble() != null && mBubbleData.getSelectedBubble().getKey().equals(entry.getKey()) ? true : false; } - void promoteBubbleFromOverflow(Bubble bubble) { + @Override + public void promoteBubbleFromOverflow(Bubble bubble) { mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK); bubble.setInflateSynchronously(mInflateSynchronously); bubble.setShouldAutoExpand(true); @@ -1041,12 +1028,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi setIsBubble(bubble, true /* isBubble */); } - /** - * Request the stack expand if needed, then select the specified Bubble as current. - * If no bubble exists for this entry, one is created. - * - * @param entry the notification for the bubble to be selected - */ + @Override public void expandStackAndSelectBubble(NotificationEntry entry) { if (mStatusBarStateListener.getCurrentState() == SHADE) { mNotifEntryToExpandOnShadeUnlock = null; @@ -1074,12 +1056,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - /** - * When a notification is marked Priority, expand the stack if needed, - * then (maybe create and) select the given bubble. - * - * @param entry the notification for the bubble to show - */ + @Override public void onUserChangedImportance(NotificationEntry entry) { try { int flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; @@ -1094,10 +1071,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - /** - * Directs a back gesture at the bubble stack. When opened, the current expanded bubble - * is forwarded a back key down/up pair. - */ + @Override public void performBackPressIfNeeded() { if (mStackView != null) { mStackView.performBackPressIfNeeded(); @@ -1140,8 +1114,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) { notif.setInterruption(); } - Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */); - inflateAndAdd(bubble, suppressFlyout, showInShade); + if (!notif.getRanking().visuallyInterruptive() + && (notif.getBubbleMetadata() != null + && !notif.getBubbleMetadata().getAutoExpandBubble()) + && mBubbleData.hasOverflowBubbleWithKey(notif.getKey())) { + // Update the bubble but don't promote it out of overflow + Bubble b = mBubbleData.getOverflowBubbleWithKey(notif.getKey()); + b.setEntry(notif); + } else { + Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */); + inflateAndAdd(bubble, suppressFlyout, showInShade); + } } void inflateAndAdd(Bubble bubble, boolean suppressFlyout, boolean showInShade) { @@ -1152,15 +1135,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mContext, mStackView, mBubbleIconFactory, false /* skipInflation */); } - /** - * Called when a user has indicated that an active notification should be shown as a bubble. - * <p> - * This method will collapse the shade, create the bubble without a flyout or dot, and suppress - * the notification from appearing in the shade. - * - * @param entry the notification to change bubble state for. - * @param shouldBubble whether the notification should show as a bubble or not. - */ + @Override public void onUserChangedBubble(@NonNull final NotificationEntry entry, boolean shouldBubble) { NotificationChannel channel = entry.getChannel(); final String appPkg = entry.getSbn().getPackageName(); @@ -1199,13 +1174,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - /** - * Removes the bubble with the given key. - * <p> - * Must be called from the main thread. - */ @MainThread - void removeBubble(String key, int reason) { + @Override + public void removeBubble(String key, int reason) { if (mBubbleData.hasAnyBubbleWithKey(key)) { mBubbleData.dismissBubbleWithKey(key, reason); } @@ -1447,16 +1418,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } }; - /** - * We intercept notification entries (including group summaries) dismissed by the user when - * there is an active bubble associated with it. We do this so that developers can still - * cancel it (and hence the bubbles associated with it). However, these intercepted - * notifications should then be hidden from the shade since the user has cancelled them, so we - * {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add - * {@link BubbleData#addSummaryToSuppress}. - * - * @return true if we want to intercept the dismissal of the entry, else false. - */ + @Override public boolean handleDismissalInterception(NotificationEntry entry) { if (entry == null) { return false; @@ -1579,10 +1541,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mStackView.updateContentDescription(); } - /** - * The display id of the expanded view, if the stack is expanded and not occluded by the - * status bar, otherwise returns {@link Display#INVALID_DISPLAY}. - */ + @Override public int getExpandedDisplayId(Context context) { if (mStackView == null) { return INVALID_DISPLAY; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index bab18ec053ee..2c3cb5f8dcb0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -284,7 +284,8 @@ public class BubbleData { } else { // Updates an existing bubble bubble.setSuppressFlyout(suppressFlyout); - doUpdate(bubble); + // If there is no flyout, we probably shouldn't show the bubble at the top + doUpdate(bubble, !suppressFlyout /* reorder */); } if (bubble.shouldAutoExpand()) { @@ -438,12 +439,12 @@ public class BubbleData { } } - private void doUpdate(Bubble bubble) { + private void doUpdate(Bubble bubble, boolean reorder) { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "doUpdate: " + bubble); } mStateChange.updatedBubble = bubble; - if (!isExpanded()) { + if (!isExpanded() && reorder) { int prevPos = mBubbles.indexOf(bubble); mBubbles.remove(bubble); mBubbles.add(0, bubble); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index ec60cbd175d0..83a816b85d78 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -127,7 +127,7 @@ public class BubbleExpandedView extends LinearLayout { private boolean mIsOverflow; - private BubbleController mBubbleController = Dependency.get(BubbleController.class); + private Bubbles mBubbles = Dependency.get(Bubbles.class); private WindowManager mWindowManager; private ActivityManager mActivityManager; @@ -168,7 +168,7 @@ public class BubbleExpandedView extends LinearLayout { + "bubble=" + getBubbleKey()); } if (mActivityView == null) { - mBubbleController.removeBubble(getBubbleKey(), + mBubbles.removeBubble(getBubbleKey(), BubbleController.DISMISS_INVALID_INTENT); return; } @@ -194,7 +194,7 @@ public class BubbleExpandedView extends LinearLayout { // the bubble again so we'll just remove it. Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() + ", " + e.getMessage() + "; removing bubble"); - mBubbleController.removeBubble(getBubbleKey(), + mBubbles.removeBubble(getBubbleKey(), BubbleController.DISMISS_INVALID_INTENT); } }); @@ -242,7 +242,7 @@ public class BubbleExpandedView extends LinearLayout { } if (mBubble != null) { // Must post because this is called from a binder thread. - post(() -> mBubbleController.removeBubble(mBubble.getKey(), + post(() -> mBubbles.removeBubble(mBubble.getKey(), BubbleController.DISMISS_TASK_FINISHED)); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java index 160addc405fa..5fdda9759659 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java @@ -60,7 +60,7 @@ public class BubbleOverflowActivity extends Activity { private TextView mEmptyStateTitle; private TextView mEmptyStateSubtitle; private ImageView mEmptyStateImage; - private BubbleController mBubbleController; + private Bubbles mBubbles; private BubbleOverflowAdapter mAdapter; private RecyclerView mRecyclerView; private List<Bubble> mOverflowBubbles = new ArrayList<>(); @@ -71,7 +71,8 @@ public class BubbleOverflowActivity extends Activity { } @Override public boolean canScrollVertically() { - if (mBubbleController.inLandscape()) { + if (getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE) { return super.canScrollVertically(); } return false; @@ -93,8 +94,8 @@ public class BubbleOverflowActivity extends Activity { } @Inject - public BubbleOverflowActivity(BubbleController controller) { - mBubbleController = controller; + public BubbleOverflowActivity(Bubbles bubbles) { + mBubbles = bubbles; } @Override @@ -131,15 +132,15 @@ public class BubbleOverflowActivity extends Activity { final int viewHeight = recyclerViewHeight / rows; mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles, - mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight); + mBubbles::promoteBubbleFromOverflow, viewWidth, viewHeight); mRecyclerView.setAdapter(mAdapter); mOverflowBubbles.clear(); - mOverflowBubbles.addAll(mBubbleController.getOverflowBubbles()); + mOverflowBubbles.addAll(mBubbles.getOverflowBubbles()); mAdapter.notifyDataSetChanged(); updateEmptyStateVisibility(); - mBubbleController.setOverflowListener(mDataListener); + mBubbles.setOverflowListener(mDataListener); updateTheme(); } @@ -209,8 +210,7 @@ public class BubbleOverflowActivity extends Activity { if (DEBUG_OVERFLOW) { Log.d(TAG, BubbleDebugConfig.formatBubblesString( - mBubbleController.getOverflowBubbles(), - null)); + mBubbles.getOverflowBubbles(), null)); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java new file mode 100644 index 000000000000..34828b384939 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubbles.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.bubbles; + +import android.annotation.NonNull; +import android.content.Context; +import android.view.Display; + +import androidx.annotation.MainThread; + +import com.android.systemui.statusbar.ScrimView; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.phone.ScrimController; + +import java.util.List; + +/** + * Interface to engage bubbles feature. + */ +public interface Bubbles { + + /** + * @return {@code true} if there is a bubble associated with the provided key and if its + * notification is hidden from the shade or there is a group summary associated with the + * provided key that is hidden from the shade because it has been dismissed but still has child + * bubbles active. + */ + boolean isBubbleNotificationSuppressedFromShade(NotificationEntry entry); + + /** + * @return {@code true} if the current notification entry same as selected bubble + * notification entry and the stack is currently expanded. + */ + boolean isBubbleExpanded(NotificationEntry entry); + + /** @return {@code true} if stack of bubbles is expanded or not. */ + boolean isStackExpanded(); + + /** + * @return the {@link ScrimView} drawn behind the bubble stack. This is managed by + * {@link ScrimController} since we want the scrim's appearance and behavior to be identical to + * that of the notification shade scrim. + */ + ScrimView getScrimForBubble(); + + /** + * @return the display id of the expanded view, if the stack is expanded and not occluded by the + * status bar, otherwise returns {@link Display#INVALID_DISPLAY}. + */ + int getExpandedDisplayId(Context context); + + /** @return Bubbles for updating overflow. */ + List<Bubble> getOverflowBubbles(); + + /** Tell the stack of bubbles to collapse. */ + void collapseStack(); + + /** + * Request the stack expand if needed, then select the specified Bubble as current. + * If no bubble exists for this entry, one is created. + * + * @param entry the notification for the bubble to be selected + */ + void expandStackAndSelectBubble(NotificationEntry entry); + + + /** + * Directs a back gesture at the bubble stack. When opened, the current expanded bubble + * is forwarded a back key down/up pair. + */ + void performBackPressIfNeeded(); + + /** Promote the provided bubbles when overflow view. */ + void promoteBubbleFromOverflow(Bubble bubble); + + /** + * We intercept notification entries (including group summaries) dismissed by the user when + * there is an active bubble associated with it. We do this so that developers can still + * cancel it (and hence the bubbles associated with it). However, these intercepted + * notifications should then be hidden from the shade since the user has cancelled them, so we + * {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add + * {@link BubbleData#addSummaryToSuppress}. + * + * @return true if we want to intercept the dismissal of the entry, else false. + */ + boolean handleDismissalInterception(NotificationEntry entry); + + /** + * Removes the bubble with the given key. + * <p> + * Must be called from the main thread. + */ + @MainThread + void removeBubble(String key, int reason); + + + /** + * When a notification is marked Priority, expand the stack if needed, + * then (maybe create and) select the given bubble. + * + * @param entry the notification for the bubble to show + */ + void onUserChangedImportance(NotificationEntry entry); + + /** + * Called when the status bar has become visible or invisible (either permanently or + * temporarily). + */ + void onStatusBarVisibilityChanged(boolean visible); + + /** + * Called when a user has indicated that an active notification should be shown as a bubble. + * <p> + * This method will collapse the shade, create the bubble without a flyout or dot, and suppress + * the notification from appearing in the shade. + * + * @param entry the notification to change bubble state for. + * @param shouldBubble whether the notification should show as a bubble or not. + */ + void onUserChangedBubble(@NonNull NotificationEntry entry, boolean shouldBubble); + + + /** See {@link BubbleController.NotifCallback}. */ + void addNotifCallback(BubbleController.NotifCallback callback); + + /** Set a listener to be notified of bubble expand events. */ + void setExpandListener(BubbleController.BubbleExpandListener listener); + + /** Set a listener to be notified of when overflow view update. */ + void setOverflowListener(BubbleData.Listener listener); +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index 5bf105368997..08902f8c7803 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -25,6 +25,7 @@ import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.bubbles.BubbleData; import com.android.systemui.bubbles.BubbleDataRepository; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; @@ -53,7 +54,7 @@ public interface BubbleModule { */ @SysUISingleton @Provides - static BubbleController newBubbleController( + static Bubbles newBubbleController( Context context, NotificationShadeWindowController notificationShadeWindowController, StatusBarStateController statusBarStateController, diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index c2d6cd445fa9..1beb875af70c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -250,13 +250,13 @@ class MediaCarouselController @Inject constructor( val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) newPlayer.view?.player?.setLayoutParams(lp) - newPlayer.bind(data) + newPlayer.bind(data, key) newPlayer.setListening(currentlyExpanded) MediaPlayerData.addMediaPlayer(key, data, newPlayer) updatePlayerToState(newPlayer, noAnimation = true) reorderAllPlayers() } else { - existingPlayer.bind(data) + existingPlayer.bind(data, key) MediaPlayerData.addMediaPlayer(key, data, existingPlayer) if (visualStabilityManager.isReorderingAllowed) { reorderAllPlayers() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index e55678dc986b..810cecca517f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -82,6 +82,7 @@ public class MediaControlPanel { private Context mContext; private PlayerViewHolder mViewHolder; + private String mKey; private MediaViewController mMediaViewController; private MediaSession.Token mToken; private MediaController mController; @@ -206,10 +207,11 @@ public class MediaControlPanel { /** * Bind this view based on the data given */ - public void bind(@NonNull MediaData data) { + public void bind(@NonNull MediaData data, String key) { if (mViewHolder == null) { return; } + mKey = key; MediaSession.Token token = data.getToken(); mBackgroundColor = data.getBackgroundColor(); if (mToken == null || !mToken.equals(token)) { @@ -359,10 +361,10 @@ public class MediaControlPanel { // Dismiss mViewHolder.getDismiss().setOnClickListener(v -> { - if (data.getNotificationKey() != null) { + if (mKey != null) { closeGuts(); mKeyguardDismissUtil.executeWhenUnlocked(() -> { - mMediaDataManagerLazy.get().dismissMediaData(data.getNotificationKey(), + mMediaDataManagerLazy.get().dismissMediaData(mKey, MediaViewController.GUTS_ANIMATION_DURATION + 100); return true; }, /* requiresShadeOpen */ true); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java index d6b831640326..af851a7b768d 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/KeyButtonView.java @@ -58,7 +58,7 @@ import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.shared.system.QuickStepContract; @@ -426,9 +426,9 @@ public class KeyButtonView extends ImageView implements ButtonInterface { if (getDisplay() != null) { displayId = getDisplay().getDisplayId(); } - // Bubble controller will give us a valid display id if it should get the back event - BubbleController bubbleController = Dependency.get(BubbleController.class); - int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext); + // Bubbles will give us a valid display id if it should get the back event + Bubbles Bubbles = Dependency.get(Bubbles.class); + int bubbleDisplayId = Bubbles.getExpandedDisplayId(mContext); if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) { displayId = bubbleDisplayId; } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 56943604e9b3..6d6d6cbfc780 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -57,7 +57,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.model.SysUiState; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.navigationbar.NavigationModeController; @@ -725,9 +725,8 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_KEYBOARD); - // Bubble controller will give us a valid display id if it should get the back event - BubbleController bubbleController = Dependency.get(BubbleController.class); - int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext); + // Bubbles will give us a valid display id if it should get the back event + final int bubbleDisplayId = Dependency.get(Bubbles.class).getExpandedDisplayId(mContext); if (bubbleDisplayId != INVALID_DISPLAY) { ev.setDisplayId(bubbleDisplayId); } else { diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 9cf2751df8ee..fb86535b4e90 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -548,16 +548,17 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize /** * Setup the ViewHost and attach the provided menu view to the ViewHost. + * @return The input token belonging to the PipMenuView. */ - public void attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) { + public IBinder attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) { if (mPipMenuSurface != null) { Log.e(TAG, "PIP Menu View already created and attached."); - return; + return null; } if (mLeash == null) { Log.e(TAG, "PiP Leash is not yet ready."); - return; + return null; } if (Looper.getMainLooper() != Looper.myLooper()) { @@ -573,6 +574,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize transaction.setRelativeLayer(mPipMenuSurface, mLeash, 1); transaction.apply(); mPipViewHost.setView(menuView, lp); + + return mPipViewHost.getSurfacePackage().getInputToken(); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 4c86ea3aac0c..6c232251e817 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -27,10 +27,12 @@ import android.content.pm.ParceledListSlice; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.Debug; +import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.MotionEvent; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import com.android.systemui.pip.PipTaskOrganizer; import com.android.systemui.pip.phone.PipMediaController.ActionListener; @@ -92,6 +94,7 @@ public class PipMenuActivityController { private int mMenuState; private PipMenuView mPipMenuView; + private IBinder mPipMenuInputToken; private ActionListener mMediaActionListener = new ActionListener() { @Override @@ -120,6 +123,7 @@ public class PipMenuActivityController { hideMenu(); mPipTaskOrganizer.detachPipMenuViewHost(); mPipMenuView = null; + mPipMenuInputToken = null; } public void onPinnedStackAnimationEnded() { @@ -133,7 +137,13 @@ public class PipMenuActivityController { mPipMenuView = new PipMenuView(mContext, this); } - mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView, getPipMenuLayoutParams(0, 0)); + + // If we haven't gotten the input toekn, that means we haven't had a success attempt + // yet at attaching the PipMenuView + if (mPipMenuInputToken == null) { + mPipMenuInputToken = mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView, + getPipMenuLayoutParams(0, 0)); + } } /** @@ -352,6 +362,13 @@ public class PipMenuActivityController { // the menu actions to be updated again. mMediaController.removeListener(mMediaActionListener); } + + try { + WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */, + mPipMenuInputToken, menuState != MENU_STATE_NONE /* grantFocus */); + } catch (RemoteException e) { + Log.e(TAG, "Unable to update focus as menu appears/disappears", e); + } } mMenuState = menuState; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java index 1c38ab338969..48ddbffa2d39 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java @@ -154,10 +154,6 @@ public class PipMenuView extends FrameLayout { expandPip(); } }); - // TODO (b/161710689): Remove this once focusability for Windowless window is working - findViewById(R.id.expand_button).setFocusable(false); - mDismissButton.setFocusable(false); - mSettingsButton.setFocusable(false); mResizeHandle = findViewById(R.id.resize_handle); mResizeHandle.setAlpha(0); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java index f911b4912e7a..1e3d871713c7 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java @@ -308,6 +308,10 @@ public class PipResizeGestureHandler { return mTmpRegion.contains(x, y); } + public boolean isUsingPinchToZoom() { + return mEnablePinchResize; + } + public boolean willStartResizeGesture(MotionEvent ev) { if (isInValidSysUiState()) { switch (ev.getActionMasked()) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 6e2c046d8fb3..1f9125da4d48 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -831,9 +831,7 @@ public class PipTouchHandler { // we store back to this snap fraction. Otherwise, we'll reset the snap // fraction and snap to the closest edge. if (resize) { - Rect expandedBounds = new Rect(mExpandedBounds); - mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds, - mMovementBounds, mExpandedMovementBounds, callback); + animateToExpandedState(callback); } } else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) { // Try and restore the PiP to the closest edge, using the saved snap fraction @@ -859,13 +857,7 @@ public class PipTouchHandler { } if (mDeferResizeToNormalBoundsUntilRotation == -1) { - Rect restoreBounds = new Rect(getUserResizeBounds()); - Rect restoredMovementBounds = new Rect(); - mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds, - mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0); - mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction, - restoredMovementBounds, mMovementBounds, false /* immediate */); - mSavedSnapFraction = -1f; + animateToUnexpandedState(getUserResizeBounds()); } } else { mSavedSnapFraction = -1f; @@ -883,6 +875,21 @@ public class PipTouchHandler { } } + private void animateToExpandedState(Runnable callback) { + Rect expandedBounds = new Rect(mExpandedBounds); + mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds, + mMovementBounds, mExpandedMovementBounds, callback); + } + + private void animateToUnexpandedState(Rect restoreBounds) { + Rect restoredMovementBounds = new Rect(); + mPipBoundsHandler.getSnapAlgorithm().getMovementBounds(restoreBounds, + mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0); + mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction, + restoredMovementBounds, mMovementBounds, false /* immediate */); + mSavedSnapFraction = -1f; + } + /** * @return the motion helper. */ @@ -1025,10 +1032,24 @@ public class PipTouchHandler { this::flingEndAction /* endAction */); } } else if (mTouchState.isDoubleTap()) { - // Expand to fullscreen if this is a double tap - // the PiP should be frozen until the transition ends - setTouchEnabled(false); - mMotionHelper.expandLeavePip(); + // If using pinch to zoom, double-tap functions as resizing between max/min size + if (mPipResizeGestureHandler.isUsingPinchToZoom()) { + final boolean toExpand = + mMotionHelper.getBounds().width() < mExpandedBounds.width() + && mMotionHelper.getBounds().height() < mExpandedBounds.height(); + mPipResizeGestureHandler.setUserResizeBounds(toExpand ? mExpandedBounds + : mNormalBounds); + if (toExpand) { + animateToExpandedState(null); + } else { + animateToUnexpandedState(mNormalBounds); + } + } else { + // Expand to fullscreen if this is a double tap + // the PiP should be frozen until the transition ends + setTouchEnabled(false); + mMotionHelper.expandLeavePip(); + } } else if (mMenuState != MENU_STATE_FULL) { if (!mTouchState.isWaitingForDoubleTap()) { // User has stalled long enough for this not to be a drag or a double tap, just diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java index 56b939df383f..a6c3221354ed 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java @@ -51,6 +51,7 @@ import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; +import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; @@ -72,6 +73,7 @@ public class CastTile extends QSTileImpl<BooleanState> { private final Callback mCallback = new Callback(); private Dialog mDialog; private boolean mWifiConnected; + private boolean mHotspotConnected; @Inject public CastTile( @@ -84,7 +86,8 @@ public class CastTile extends QSTileImpl<BooleanState> { QSLogger qsLogger, CastController castController, KeyguardStateController keyguardStateController, - NetworkController networkController + NetworkController networkController, + HotspotController hotspotController ) { super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); @@ -95,6 +98,7 @@ public class CastTile extends QSTileImpl<BooleanState> { mController.observe(this, mCallback); mKeyguard.observe(this, mCallback); mNetworkController.observe(this, mSignalCallback); + hotspotController.observe(this, mHotspotCallback); } @Override @@ -222,7 +226,7 @@ public class CastTile extends QSTileImpl<BooleanState> { } state.icon = ResourceIcon.get(state.value ? R.drawable.ic_cast_connected : R.drawable.ic_cast); - if (mWifiConnected || state.value) { + if (canCastToWifi() || state.value) { state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; if (!state.value) { state.secondaryLabel = ""; @@ -258,6 +262,10 @@ public class CastTile extends QSTileImpl<BooleanState> { : mContext.getString(R.string.quick_settings_cast_device_default_name); } + private boolean canCastToWifi() { + return mWifiConnected || mHotspotConnected; + } + private final NetworkController.SignalCallback mSignalCallback = new NetworkController.SignalCallback() { @Override @@ -269,7 +277,25 @@ public class CastTile extends QSTileImpl<BooleanState> { boolean enabledAndConnected = enabled && qsIcon.visible; if (enabledAndConnected != mWifiConnected) { mWifiConnected = enabledAndConnected; - refreshState(); + // Hotspot is not connected, so changes here should update + if (!mHotspotConnected) { + refreshState(); + } + } + } + }; + + private final HotspotController.Callback mHotspotCallback = + new HotspotController.Callback() { + @Override + public void onHotspotChanged(boolean enabled, int numDevices) { + boolean enabledAndConnected = enabled && numDevices > 0; + if (enabledAndConnected != mHotspotConnected) { + mHotspotConnected = enabledAndConnected; + // Wifi is not connected, so changes here should update + if (!mWifiConnected) { + refreshState(); + } } } }; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index aa435165d3f3..f11683dedbda 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -233,21 +233,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } @Override - public void onSplitScreenInvoked() { - if (!verifyCaller("onSplitScreenInvoked")) { - return; - } - long token = Binder.clearCallingIdentity(); - try { - mSplitScreenOptional.ifPresent(splitScreen -> { - splitScreen.onDockedFirstAnimationFrame(); - }); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override public void onOverviewShown(boolean fromHome) { if (!verifyCaller("onOverviewShown")) { return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index 38c7e5c50f63..53179ba4be90 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -26,7 +26,7 @@ import android.view.View; import android.view.ViewGroup; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.StatusBarModule; @@ -47,6 +47,7 @@ import com.android.systemui.util.Assert; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.Stack; /** @@ -84,7 +85,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle * possible. */ private final boolean mAlwaysExpandNonGroupedNotification; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final DynamicPrivacyController mDynamicPrivacyController; private final KeyguardBypassController mBypassController; private final ForegroundServiceSectionController mFgsSectionController; @@ -112,7 +113,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle StatusBarStateController statusBarStateController, NotificationEntryManager notificationEntryManager, KeyguardBypassController bypassController, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, DynamicPrivacyController privacyController, ForegroundServiceSectionController fgsSectionController, DynamicChildBindController dynamicChildBindController, @@ -130,7 +131,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle Resources res = context.getResources(); mAlwaysExpandNonGroupedNotification = res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications); - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mDynamicPrivacyController = privacyController; mDynamicChildBindController = dynamicChildBindController; mLowPriorityInflationHelper = lowPriorityInflationHelper; @@ -157,8 +158,10 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle final int N = activeNotifications.size(); for (int i = 0; i < N; i++) { NotificationEntry ent = activeNotifications.get(i); + final boolean isBubbleNotificationSuppressedFromShade = mBubblesOptional.isPresent() + && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(ent); if (ent.isRowDismissed() || ent.isRowRemoved() - || mBubbleController.isBubbleNotificationSuppressedFromShade(ent) + || isBubbleNotificationSuppressedFromShade || mFgsSectionController.hasEntry(ent)) { // we don't want to update removed notifications because they could // temporarily become children if they were isolated before. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index d15b8476b3c5..969cd90e61d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -21,7 +21,7 @@ import android.content.Context; import android.os.Handler; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.media.MediaDataManager; @@ -59,6 +59,8 @@ import com.android.systemui.tracing.ProtoTracer; import com.android.systemui.util.DeviceConfigProxy; import com.android.systemui.util.concurrency.DelayableExecutor; +import java.util.Optional; + import dagger.Binds; import dagger.Lazy; import dagger.Module; @@ -162,7 +164,7 @@ public interface StatusBarDependenciesModule { StatusBarStateController statusBarStateController, NotificationEntryManager notificationEntryManager, KeyguardBypassController bypassController, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, DynamicPrivacyController privacyController, ForegroundServiceSectionController fgsSectionController, DynamicChildBindController dynamicChildBindController, @@ -177,7 +179,7 @@ public interface StatusBarDependenciesModule { statusBarStateController, notificationEntryManager, bypassController, - bubbleController, + bubblesOptional, privacyController, fgsSectionController, dynamicChildBindController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index d364689a65d4..7d8979ca1129 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -22,7 +22,7 @@ import android.util.Log; import android.view.View; import com.android.systemui.DejankUtils; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.phone.StatusBar; @@ -38,19 +38,19 @@ import javax.inject.Inject; public final class NotificationClicker implements View.OnClickListener { private static final String TAG = "NotificationClicker"; - private final BubbleController mBubbleController; private final NotificationClickerLogger mLogger; - private final Optional<StatusBar> mStatusBar; + private final Optional<StatusBar> mStatusBarOptional; + private final Optional<Bubbles> mBubblesOptional; private final NotificationActivityStarter mNotificationActivityStarter; private NotificationClicker( - BubbleController bubbleController, NotificationClickerLogger logger, - Optional<StatusBar> statusBar, + Optional<StatusBar> statusBarOptional, + Optional<Bubbles> bubblesOptional, NotificationActivityStarter notificationActivityStarter) { - mBubbleController = bubbleController; mLogger = logger; - mStatusBar = statusBar; + mStatusBarOptional = statusBarOptional; + mBubblesOptional = bubblesOptional; mNotificationActivityStarter = notificationActivityStarter; } @@ -61,7 +61,7 @@ public final class NotificationClicker implements View.OnClickListener { return; } - mStatusBar.ifPresent(statusBar -> statusBar.wakeUpIfDozing( + mStatusBarOptional.ifPresent(statusBar -> statusBar.wakeUpIfDozing( SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK")); final ExpandableNotificationRow row = (ExpandableNotificationRow) v; @@ -92,8 +92,8 @@ public final class NotificationClicker implements View.OnClickListener { row.setJustClicked(true); DejankUtils.postAfterTraversal(() -> row.setJustClicked(false)); - if (!row.getEntry().isBubble()) { - mBubbleController.collapseStack(); + if (!row.getEntry().isBubble() && mBubblesOptional.isPresent()) { + mBubblesOptional.get().collapseStack(); } mNotificationActivityStarter.onNotificationClicked(entry.getSbn(), row); @@ -118,26 +118,23 @@ public final class NotificationClicker implements View.OnClickListener { /** Daggerized builder for NotificationClicker. */ public static class Builder { - private final BubbleController mBubbleController; private final NotificationClickerLogger mLogger; @Inject - public Builder( - BubbleController bubbleController, - NotificationClickerLogger logger) { - mBubbleController = bubbleController; + public Builder(NotificationClickerLogger logger) { mLogger = logger; } /** Builds an instance. */ public NotificationClicker build( - Optional<StatusBar> statusBar, + Optional<StatusBar> statusBarOptional, + Optional<Bubbles> bubblesOptional, NotificationActivityStarter notificationActivityStarter ) { return new NotificationClicker( - mBubbleController, mLogger, - statusBar, + statusBarOptional, + bubblesOptional, notificationActivityStarter); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java index 4ddc1dc8498d..0455b0f18afc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; @@ -26,6 +27,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Di import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import javax.inject.Inject; @@ -54,7 +56,7 @@ import javax.inject.Inject; public class BubbleCoordinator implements Coordinator { private static final String TAG = "BubbleCoordinator"; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final NotifCollection mNotifCollection; private final Set<String> mInterceptedDismissalEntries = new HashSet<>(); private NotifPipeline mNotifPipeline; @@ -62,9 +64,9 @@ public class BubbleCoordinator implements Coordinator { @Inject public BubbleCoordinator( - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, NotifCollection notifCollection) { - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mNotifCollection = notifCollection; } @@ -73,13 +75,17 @@ public class BubbleCoordinator implements Coordinator { mNotifPipeline = pipeline; mNotifPipeline.addNotificationDismissInterceptor(mDismissInterceptor); mNotifPipeline.addFinalizeFilter(mNotifFilter); - mBubbleController.addNotifCallback(mNotifCallback); + if (mBubblesOptional.isPresent()) { + mBubblesOptional.get().addNotifCallback(mNotifCallback); + } + } private final NotifFilter mNotifFilter = new NotifFilter(TAG) { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - return mBubbleController.isBubbleNotificationSuppressedFromShade(entry); + return mBubblesOptional.isPresent() + && mBubblesOptional.get().isBubbleNotificationSuppressedFromShade(entry); } }; @@ -97,7 +103,8 @@ public class BubbleCoordinator implements Coordinator { @Override public boolean shouldInterceptDismissal(NotificationEntry entry) { // for experimental bubbles - if (mBubbleController.handleDismissalInterception(entry)) { + if (mBubblesOptional.isPresent() + && mBubblesOptional.get().handleDismissalInterception(entry)) { mInterceptedDismissalEntries.add(entry.getKey()); return true; } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java index 21d54c85160b..490989dbb39e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java @@ -21,9 +21,8 @@ import android.service.notification.StatusBarNotification; import android.util.ArraySet; import android.util.Log; -import com.android.systemui.Dependency; import com.android.systemui.Dumpable; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; @@ -43,6 +42,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import javax.inject.Inject; @@ -64,25 +64,20 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, new ArraySet<>(); private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>(); private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier; + private final Optional<Lazy<Bubbles>> mBubblesOptional; private int mBarState = -1; private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>(); private HeadsUpManager mHeadsUpManager; private boolean mIsUpdatingUnchangedGroup; - @Nullable private BubbleController mBubbleController = null; @Inject public NotificationGroupManagerLegacy( StatusBarStateController statusBarStateController, - Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier) { + Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier, + Optional<Lazy<Bubbles>> bubblesOptional) { statusBarStateController.addCallback(this); mPeopleNotificationIdentifier = peopleNotificationIdentifier; - } - - private BubbleController getBubbleController() { - if (mBubbleController == null) { - mBubbleController = Dependency.get(BubbleController.class); - } - return mBubbleController; + mBubblesOptional = bubblesOptional; } /** @@ -247,7 +242,8 @@ public class NotificationGroupManagerLegacy implements OnHeadsUpChangedListener, int childCount = 0; boolean hasBubbles = false; for (NotificationEntry entry : group.children.values()) { - if (!getBubbleController().isBubbleNotificationSuppressedFromShade(entry)) { + if (mBubblesOptional.isPresent() && !mBubblesOptional.get().get() + .isBubbleNotificationSuppressedFromShade(entry)) { childCount++; } else { hasBubbles = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt index 498b8e884b17..1311e3e756dc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt @@ -17,11 +17,13 @@ package com.android.systemui.statusbar.notification.collection.render import android.annotation.StringRes +import android.content.Intent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.android.systemui.R -import com.android.systemui.statusbar.notification.dagger.HeaderClick +import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.statusbar.notification.dagger.HeaderClickAction import com.android.systemui.statusbar.notification.dagger.HeaderText import com.android.systemui.statusbar.notification.dagger.NodeLabel import com.android.systemui.statusbar.notification.dagger.SectionHeaderScope @@ -39,11 +41,19 @@ internal class SectionHeaderNodeControllerImpl @Inject constructor( @NodeLabel override val nodeLabel: String, private val layoutInflater: LayoutInflater, @HeaderText @StringRes private val headerTextResId: Int, - @HeaderClick private val onHeaderClickListener: View.OnClickListener + private val activityStarter: ActivityStarter, + @HeaderClickAction private val clickIntentAction: String ) : NodeController, SectionHeaderController { private var _view: SectionHeaderView? = null private var clearAllClickListener: View.OnClickListener? = null + private val onHeaderClickListener = View.OnClickListener { + activityStarter.startActivity( + Intent(clickIntentAction), + true /* onlyProvisioned */, + true /* dismissShade */, + Intent.FLAG_ACTIVITY_SINGLE_TOP) + } override fun reinflateView(parent: ViewGroup) { var oldPos = -1 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt index 179d49cb55a1..2a9cfd034dce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt @@ -17,12 +17,9 @@ package com.android.systemui.statusbar.notification.dagger import android.annotation.StringRes -import android.content.Intent import android.provider.Settings -import android.view.View import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.notification.collection.render.NodeController import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController import com.android.systemui.statusbar.notification.collection.render.SectionHeaderNodeControllerImpl @@ -39,18 +36,6 @@ import javax.inject.Scope object NotificationSectionHeadersModule { @Provides - @HeaderClick - @JvmStatic fun providesOnHeaderClickListener( - activityStarter: ActivityStarter - ) = View.OnClickListener { - activityStarter.startActivity( - Intent(Settings.ACTION_NOTIFICATION_SETTINGS), - true /* onlyProvisioned */, - true /* dismissShade */, - Intent.FLAG_ACTIVITY_SINGLE_TOP) - } - - @Provides @IncomingHeader @SysUISingleton @JvmStatic fun providesIncomingHeaderSubcomponent( @@ -58,6 +43,7 @@ object NotificationSectionHeadersModule { ) = builder.get() .nodeLabel("incoming header") .headerText(R.string.notification_section_header_incoming) + .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS) .build() @Provides @@ -68,6 +54,7 @@ object NotificationSectionHeadersModule { ) = builder.get() .nodeLabel("alerting header") .headerText(R.string.notification_section_header_alerting) + .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS) .build() @Provides @@ -78,6 +65,7 @@ object NotificationSectionHeadersModule { ) = builder.get() .nodeLabel("people header") .headerText(R.string.notification_section_header_conversations) + .clickIntentAction(Settings.ACTION_CONVERSATION_SETTINGS) .build() @Provides @@ -88,6 +76,7 @@ object NotificationSectionHeadersModule { ) = builder.get() .nodeLabel("silent header") .headerText(R.string.notification_section_header_gentle) + .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS) .build() @Provides @@ -151,6 +140,7 @@ interface SectionHeaderControllerSubcomponent { fun build(): SectionHeaderControllerSubcomponent @BindsInstance fun nodeLabel(@NodeLabel nodeLabel: String): Builder @BindsInstance fun headerText(@HeaderText @StringRes headerText: Int): Builder + @BindsInstance fun clickIntentAction(@HeaderClickAction clickIntentAction: String): Builder } } @@ -188,7 +178,7 @@ annotation class NodeLabel @Qualifier @Retention(AnnotationRetention.BINARY) -annotation class HeaderClick +annotation class HeaderClickAction @Scope @Retention(AnnotationRetention.BINARY) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 01333f0a47d5..4fff99b482d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -26,7 +26,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.UiEventLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -74,6 +74,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; +import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Provider; @@ -132,7 +133,7 @@ public interface NotificationsModule { UserContextProvider contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider, AssistantFeedbackController assistantFeedbackController, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, UiEventLogger uiEventLogger, OnUserInteractionCallback onUserInteractionCallback) { return new NotificationGutsManager( @@ -149,7 +150,7 @@ public interface NotificationsModule { contextTracker, builderProvider, assistantFeedbackController, - bubbleController, + bubblesOptional, uiEventLogger, onUserInteractionCallback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt index 9da8b8a3fd92..049b471aa7cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.init import android.service.notification.StatusBarNotification +import com.android.systemui.bubbles.Bubbles import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption import com.android.systemui.statusbar.NotificationPresenter import com.android.systemui.statusbar.notification.NotificationActivityStarter @@ -25,6 +26,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.phone.StatusBar import java.io.FileDescriptor import java.io.PrintWriter +import java.util.Optional /** * The master controller for all notifications-related work @@ -35,6 +37,7 @@ import java.io.PrintWriter interface NotificationsController { fun initialize( statusBar: StatusBar, + bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, notificationActivityStarter: NotificationActivityStarter, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 9fb292878553..45a5d1044b9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.init import android.service.notification.StatusBarNotification +import com.android.systemui.bubbles.Bubbles import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption import com.android.systemui.statusbar.FeatureFlags @@ -75,6 +76,7 @@ class NotificationsControllerImpl @Inject constructor( override fun initialize( statusBar: StatusBar, + bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, notificationActivityStarter: NotificationActivityStarter, @@ -90,7 +92,8 @@ class NotificationsControllerImpl @Inject constructor( listController.bind() notificationRowBinder.setNotificationClicker( - clickerBuilder.build(Optional.of(statusBar), notificationActivityStarter)) + clickerBuilder.build( + Optional.of(statusBar), bubblesOptional, notificationActivityStarter)) notificationRowBinder.setUpWithPresenter( presenter, listContainer, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt index ded855dd84f9..7569c1bdbb73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.notification.init import android.service.notification.StatusBarNotification +import com.android.systemui.bubbles.Bubbles import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption import com.android.systemui.statusbar.NotificationListener import com.android.systemui.statusbar.NotificationPresenter @@ -26,6 +27,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.phone.StatusBar import java.io.FileDescriptor import java.io.PrintWriter +import java.util.Optional import javax.inject.Inject /** @@ -37,6 +39,7 @@ class NotificationsControllerStub @Inject constructor( override fun initialize( statusBar: StatusBar, + bubblesOptional: Optional<Bubbles>, presenter: NotificationPresenter, listContainer: NotificationListContainer, notificationActivityStarter: NotificationActivityStarter, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 811a72de093c..113c115c44d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -72,7 +72,7 @@ import com.android.internal.widget.CachingIconView; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginListener; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; @@ -1074,7 +1074,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return new View.OnClickListener() { @Override public void onClick(View v) { - Dependency.get(BubbleController.class) + Dependency.get(Bubbles.class) .onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */); mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index b19997d15664..07a4a188bc48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -67,7 +67,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.notification.NotificationChannelHelper; @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import java.lang.annotation.Retention; +import java.util.Optional; import javax.inject.Provider; @@ -93,7 +94,7 @@ public class NotificationConversationInfo extends LinearLayout implements private OnUserInteractionCallback mOnUserInteractionCallback; private Handler mMainHandler; private Handler mBgHandler; - private BubbleController mBubbleController; + private Optional<Bubbles> mBubblesOptional; private String mPackageName; private String mAppName; private int mAppUid; @@ -222,7 +223,7 @@ public class NotificationConversationInfo extends LinearLayout implements @Main Handler mainHandler, @Background Handler bgHandler, OnConversationSettingsClickListener onConversationSettingsClickListener, - BubbleController bubbleController) { + Optional<Bubbles> bubblesOptional) { mSelectedAction = -1; mINotificationManager = iNotificationManager; mOnUserInteractionCallback = onUserInteractionCallback; @@ -241,7 +242,7 @@ public class NotificationConversationInfo extends LinearLayout implements mIconFactory = conversationIconFactory; mUserContext = userContext; mBubbleMetadata = bubbleMetadata; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mBuilderProvider = builderProvider; mMainHandler = mainHandler; mBgHandler = bgHandler; @@ -640,9 +641,11 @@ public class NotificationConversationInfo extends LinearLayout implements mINotificationManager.setBubblesAllowed(mAppPkg, mAppUid, BUBBLE_PREFERENCE_SELECTED); } - post(() -> { - mBubbleController.onUserChangedImportance(mEntry); - }); + if (mBubblesOptional.isPresent()) { + post(() -> { + mBubblesOptional.get().onUserChangedImportance(mEntry); + }); + } } mChannelToUpdate.setImportance(Math.max( mChannelToUpdate.getOriginalImportance(), IMPORTANCE_DEFAULT)); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 7d418f30e4c5..373f20e6ba96 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -47,7 +47,7 @@ import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; @@ -70,6 +70,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.Optional; import javax.inject.Provider; @@ -116,7 +117,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final Lazy<StatusBar> mStatusBarLazy; private final Handler mMainHandler; private final Handler mBgHandler; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private Runnable mOpenRunnable; private final INotificationManager mNotificationManager; private final LauncherApps mLauncherApps; @@ -141,7 +142,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx UserContextProvider contextTracker, Provider<PriorityOnboardingDialogController.Builder> builderProvider, AssistantFeedbackController assistantFeedbackController, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, UiEventLogger uiEventLogger, OnUserInteractionCallback onUserInteractionCallback) { mContext = context; @@ -157,7 +158,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mBuilderProvider = builderProvider; mChannelEditorDialogController = channelEditorDialogController; mAssistantFeedbackController = assistantFeedbackController; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mUiEventLogger = uiEventLogger; mOnUserInteractionCallback = onUserInteractionCallback; } @@ -490,7 +491,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mMainHandler, mBgHandler, onConversationSettingsListener, - mBubbleController); + mBubblesOptional); } /** 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 b47c59acb82d..0a366c9bb380 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -85,8 +85,6 @@ import com.android.systemui.statusbar.policy.PreviewInflater; import com.android.systemui.tuner.LockscreenFragment.LockButtonFactory; import com.android.systemui.tuner.TunerService; -import java.util.concurrent.Executor; - /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status * text. @@ -561,7 +559,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } }; if (!mKeyguardStateController.canDismissLockScreen()) { - Dependency.get(Executor.class).execute(runnable); + Dependency.get(Dependency.BACKGROUND_EXECUTOR).execute(runnable); } else { boolean dismissShade = !TextUtils.isEmpty(mRightButtonStr) && Dependency.get(TunerService.class).getValue(LOCKSCREEN_RIGHT_UNLOCK, 1) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index bda35fb0a48e..d1c83555c062 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -19,7 +19,7 @@ import com.android.internal.util.ContrastColorUtil; import com.android.settingslib.Utils; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.demomode.DemoMode; import com.android.systemui.demomode.DemoModeController; @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import javax.inject.Inject; @@ -65,7 +66,7 @@ public class NotificationIconAreaController implements private final NotificationWakeUpCoordinator mWakeUpCoordinator; private final KeyguardBypassController mBypassController; private final DozeParameters mDozeParameters; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final StatusBarWindowController mStatusBarWindowController; private int mIconSize; @@ -114,7 +115,7 @@ public class NotificationIconAreaController implements NotificationMediaManager notificationMediaManager, NotificationListener notificationListener, DozeParameters dozeParameters, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, DemoModeController demoModeController, DarkIconDispatcher darkIconDispatcher, StatusBarWindowController statusBarWindowController) { @@ -127,7 +128,7 @@ public class NotificationIconAreaController implements mWakeUpCoordinator = wakeUpCoordinator; wakeUpCoordinator.addListener(this); mBypassController = keyguardBypassController; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mDemoModeController = demoModeController; mDemoModeController.addCallback(this); mStatusBarWindowController = statusBarWindowController; @@ -298,7 +299,7 @@ public class NotificationIconAreaController implements || !entry.isPulseSuppressed())) { return false; } - if (mBubbleController.isBubbleExpanded(entry)) { + if (mBubblesOptional.isPresent() && mBubblesOptional.get().isBubbleExpanded(entry)) { return false; } return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index e95cf2806691..4af27877c201 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -34,6 +34,8 @@ import android.view.ViewTreeObserver; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; +import androidx.annotation.Nullable; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.colorextraction.ColorExtractor.GradientColors; @@ -139,6 +141,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo private ScrimView mScrimInFront; private ScrimView mScrimBehind; + @Nullable private ScrimView mScrimForBubble; private Runnable mScrimBehindChangeRunnable; @@ -238,7 +241,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo * Attach the controller to the supplied views. */ public void attachViews( - ScrimView scrimBehind, ScrimView scrimInFront, ScrimView scrimForBubble) { + ScrimView scrimBehind, ScrimView scrimInFront, @Nullable ScrimView scrimForBubble) { mScrimBehind = scrimBehind; mScrimInFront = scrimInFront; mScrimForBubble = scrimForBubble; @@ -258,7 +261,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mScrimBehind.setDefaultFocusHighlightEnabled(false); mScrimInFront.setDefaultFocusHighlightEnabled(false); - mScrimForBubble.setDefaultFocusHighlightEnabled(false); + if (mScrimForBubble != null) { + mScrimForBubble.setDefaultFocusHighlightEnabled(false); + } updateScrims(); mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); } @@ -455,7 +460,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo } } - private void setOrAdaptCurrentAnimation(View scrim) { + private void setOrAdaptCurrentAnimation(@Nullable View scrim) { + if (scrim == null) { + return; + } + float alpha = getCurrentScrimAlpha(scrim); if (isAnimating(scrim)) { // Adapt current animation. @@ -606,11 +615,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo // Only animate scrim color if the scrim view is actually visible boolean animateScrimInFront = mScrimInFront.getViewAlpha() != 0 && !mBlankScreen; boolean animateScrimBehind = mScrimBehind.getViewAlpha() != 0 && !mBlankScreen; - boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen; mScrimInFront.setColors(mColors, animateScrimInFront); mScrimBehind.setColors(mColors, animateScrimBehind); - mScrimForBubble.setColors(mColors, animateScrimForBubble); // Calculate minimum scrim opacity for white or black text. int textColor = mColors.supportsDarkText() ? Color.BLACK : Color.WHITE; @@ -632,7 +639,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo } setScrimAlpha(mScrimInFront, mInFrontAlpha); setScrimAlpha(mScrimBehind, mBehindAlpha); - setScrimAlpha(mScrimForBubble, mBubbleAlpha); + + if (mScrimForBubble != null) { + boolean animateScrimForBubble = mScrimForBubble.getViewAlpha() != 0 && !mBlankScreen; + mScrimForBubble.setColors(mColors, animateScrimForBubble); + setScrimAlpha(mScrimForBubble, mBubbleAlpha); + } // The animation could have all already finished, let's call onFinished just in case onFinished(); dispatchScrimsVisible(); @@ -828,12 +840,14 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mBubbleTint = Color.TRANSPARENT; updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint); updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint); - updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint); + if (mScrimForBubble != null) { + updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint); + } } } - private boolean isAnimating(View scrim) { - return scrim.getTag(TAG_KEY_ANIM) != null; + private boolean isAnimating(@Nullable View scrim) { + return scrim != null && scrim.getTag(TAG_KEY_ANIM) != null; } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index 2db36f4a62f8..fc91c16f1a48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.phone; import android.graphics.Color; import android.os.Trace; +import androidx.annotation.Nullable; + import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -212,7 +214,9 @@ public enum ScrimState { // Set all scrims black, before they fade transparent. updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */); updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */); - updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */); + if (mScrimForBubble != null) { + updateScrimColor(mScrimForBubble, 1f /* alpha */, Color.BLACK /* tint */); + } // Scrims should still be black at the end of the transition. mFrontTint = Color.BLACK; @@ -258,7 +262,7 @@ public enum ScrimState { float mDefaultScrimAlpha; ScrimView mScrimInFront; ScrimView mScrimBehind; - ScrimView mScrimForBubble; + @Nullable ScrimView mScrimForBubble; DozeParameters mDozeParameters; DockManager mDockManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java index 1ce22194878f..af2f3e55c9ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeControllerImpl.java @@ -22,7 +22,7 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import com.android.systemui.assist.AssistManager; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; import java.util.ArrayList; +import java.util.Optional; import javax.inject.Inject; @@ -50,7 +51,7 @@ public class ShadeControllerImpl implements ShadeController { private final int mDisplayId; protected final Lazy<StatusBar> mStatusBarLazy; private final Lazy<AssistManager> mAssistManagerLazy; - private final Lazy<BubbleController> mBubbleControllerLazy; + private final Optional<Lazy<Bubbles>> mBubblesOptional; private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>(); @@ -63,7 +64,7 @@ public class ShadeControllerImpl implements ShadeController { WindowManager windowManager, Lazy<StatusBar> statusBarLazy, Lazy<AssistManager> assistManagerLazy, - Lazy<BubbleController> bubbleControllerLazy + Optional<Lazy<Bubbles>> bubblesOptional ) { mCommandQueue = commandQueue; mStatusBarStateController = statusBarStateController; @@ -73,7 +74,7 @@ public class ShadeControllerImpl implements ShadeController { // TODO: Remove circular reference to StatusBar when possible. mStatusBarLazy = statusBarLazy; mAssistManagerLazy = assistManagerLazy; - mBubbleControllerLazy = bubbleControllerLazy; + mBubblesOptional = bubblesOptional; } @Override @@ -133,8 +134,8 @@ public class ShadeControllerImpl implements ShadeController { getStatusBar().getNotificationShadeWindowViewController().cancelExpandHelper(); getStatusBarView().collapsePanel(true /* animate */, delayed, speedUpFactor); - } else { - mBubbleControllerLazy.get().collapseStack(); + } else if (mBubblesOptional.isPresent()) { + mBubblesOptional.get().get().collapseStack(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 8254b7f5b32a..994af090d21f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -147,6 +147,7 @@ import com.android.systemui.SystemUI; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -649,7 +650,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected StatusBarNotificationPresenter mPresenter; private NotificationActivityStarter mNotificationActivityStarter; private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final BubbleController.BubbleExpandListener mBubbleExpandListener; private ActivityIntentHelper mActivityIntentHelper; @@ -698,7 +699,7 @@ public class StatusBar extends SystemUI implements DemoMode, WakefulnessLifecycle wakefulnessLifecycle, SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, @@ -778,7 +779,7 @@ public class StatusBar extends SystemUI implements DemoMode, mWakefulnessLifecycle = wakefulnessLifecycle; mStatusBarStateController = statusBarStateController; mVibratorHelper = vibratorHelper; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mVisualStabilityManager = visualStabilityManager; mDeviceProvisionedController = deviceProvisionedController; mNavigationBarController = navigationBarController; @@ -834,7 +835,10 @@ public class StatusBar extends SystemUI implements DemoMode, mWakefulnessLifecycle.addObserver(mWakefulnessObserver); mUiModeManager = mContext.getSystemService(UiModeManager.class); mBypassHeadsUpNotifier.setUp(); - mBubbleController.setExpandListener(mBubbleExpandListener); + if (mBubblesOptional.isPresent()) { + mBubblesOptional.get().setExpandListener(mBubbleExpandListener); + } + mActivityIntentHelper = new ActivityIntentHelper(mContext); mColorExtractor.addOnColorsChangedListener(this); @@ -1145,7 +1149,8 @@ public class StatusBar extends SystemUI implements DemoMode, ScrimView scrimBehind = mNotificationShadeWindowView.findViewById(R.id.scrim_behind); ScrimView scrimInFront = mNotificationShadeWindowView.findViewById(R.id.scrim_in_front); - ScrimView scrimForBubble = mBubbleController.getScrimForBubble(); + ScrimView scrimForBubble = mBubblesOptional.isPresent() + ? mBubblesOptional.get().getScrimForBubble() : null; mScrimController.setScrimVisibleListener(scrimsVisible -> { mNotificationShadeWindowController.setScrimsVisibility(scrimsVisible); @@ -1341,6 +1346,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationsController.initialize( this, + mBubblesOptional, mPresenter, mStackScrollerController.getNotificationListContainer(), mNotificationActivityStarter, @@ -2491,10 +2497,12 @@ public class StatusBar extends SystemUI implements DemoMode, /** Temporarily hides Bubbles if the status bar is hidden. */ private void updateBubblesVisibility() { - mBubbleController.onStatusBarVisibilityChanged( - mStatusBarMode != MODE_LIGHTS_OUT - && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT - && !mStatusBarWindowHidden); + if (mBubblesOptional.isPresent()) { + mBubblesOptional.get().onStatusBarVisibilityChanged( + mStatusBarMode != MODE_LIGHTS_OUT + && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT + && !mStatusBarWindowHidden); + } } void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState, @@ -2817,8 +2825,8 @@ public class StatusBar extends SystemUI implements DemoMode, if (mRemoteInputManager.getController() != null) { mRemoteInputManager.getController().closeRemoteInputs(); } - if (mBubbleController.isStackExpanded()) { - mBubbleController.collapseStack(); + if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) { + mBubblesOptional.get().collapseStack(); } if (mLockscreenUserManager.isCurrentProfile(getSendingUserId())) { int flags = CommandQueue.FLAG_EXCLUDE_NONE; @@ -2833,9 +2841,9 @@ public class StatusBar extends SystemUI implements DemoMode, if (mNotificationShadeWindowController != null) { mNotificationShadeWindowController.setNotTouchable(false); } - if (mBubbleController.isStackExpanded()) { + if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) { // Post to main thread handler, since updating the UI. - mMainThreadHandler.post(() -> mBubbleController.collapseStack()); + mMainThreadHandler.post(() -> mBubblesOptional.get().collapseStack()); } finishBarAnimations(); resetUserExpandedStates(); @@ -3535,8 +3543,8 @@ public class StatusBar extends SystemUI implements DemoMode, if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) { if (mNotificationPanelViewController.canPanelBeCollapsed()) { mShadeController.animateCollapsePanels(); - } else { - mBubbleController.performBackPressIfNeeded(); + } else if (mBubblesOptional.isPresent()) { + mBubblesOptional.get().performBackPressIfNeeded(); } return true; } @@ -4054,7 +4062,7 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController.transitionTo(ScrimState.AOD); } else if (mIsKeyguard && !unlocking) { mScrimController.transitionTo(ScrimState.KEYGUARD); - } else if (mBubbleController.isStackExpanded()) { + } else if (mBubblesOptional.isPresent() && mBubblesOptional.get().isStackExpanded()) { mScrimController.transitionTo(ScrimState.BUBBLE_EXPANDED, mUnlockScrimCallback); } else { mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 737cdeba797a..aa01642e5c17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -48,7 +48,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.EventLogTags; import com.android.systemui.assist.AssistManager; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; @@ -77,6 +77,7 @@ import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback import com.android.systemui.statusbar.policy.HeadsUpUtil; import com.android.systemui.statusbar.policy.KeyguardStateController; +import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -103,7 +104,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; private final IDreamManager mDreamManager; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final Lazy<AssistManager> mAssistManagerLazy; private final NotificationRemoteInputManager mRemoteInputManager; private final GroupMembershipManager mGroupMembershipManager; @@ -141,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, IDreamManager dreamManager, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, GroupMembershipManager groupMembershipManager, @@ -175,7 +176,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; mDreamManager = dreamManager; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mAssistManagerLazy = assistManagerLazy; mRemoteInputManager = remoteInputManager; mGroupMembershipManager = groupMembershipManager; @@ -386,11 +387,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } private void expandBubbleStackOnMainThread(NotificationEntry entry) { + if (!mBubblesOptional.isPresent()) { + return; + } + if (Looper.getMainLooper().isCurrentThread()) { - mBubbleController.expandStackAndSelectBubble(entry); + mBubblesOptional.get().expandStackAndSelectBubble(entry); } else { - mMainThreadHandler.post( - () -> mBubbleController.expandStackAndSelectBubble(entry)); + mMainThreadHandler.post(() -> mBubblesOptional.get().expandStackAndSelectBubble(entry)); } } @@ -602,7 +606,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; private final IDreamManager mDreamManager; - private final BubbleController mBubbleController; + private final Optional<Bubbles> mBubblesOptional; private final Lazy<AssistManager> mAssistManagerLazy; private final NotificationRemoteInputManager mRemoteInputManager; private final GroupMembershipManager mGroupMembershipManager; @@ -639,7 +643,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, IDreamManager dreamManager, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, Lazy<AssistManager> assistManagerLazy, NotificationRemoteInputManager remoteInputManager, GroupMembershipManager groupMembershipManager, @@ -669,7 +673,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; mDreamManager = dreamManager; - mBubbleController = bubbleController; + mBubblesOptional = bubblesOptional; mAssistManagerLazy = assistManagerLazy; mRemoteInputManager = remoteInputManager; mGroupMembershipManager = groupMembershipManager; @@ -725,7 +729,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mStatusBarKeyguardViewManager, mKeyguardManager, mDreamManager, - mBubbleController, + mBubblesOptional, mAssistManagerLazy, mRemoteInputManager, mGroupMembershipManager, @@ -736,12 +740,10 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mLockPatternUtils, mRemoteInputCallback, mActivityIntentHelper, - mFeatureFlags, mMetricsLogger, mLogger, mOnUserInteractionCallback, - mStatusBar, mNotificationPresenter, mNotificationPanelViewController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index b7f83145f477..3f29a4ea5b00 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -31,7 +31,7 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.InitController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.UiBackground; @@ -156,7 +156,7 @@ public interface StatusBarPhoneModule { WakefulnessLifecycle wakefulnessLifecycle, SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper, - BubbleController bubbleController, + Optional<Bubbles> bubblesOptional, VisualStabilityManager visualStabilityManager, DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, @@ -235,7 +235,7 @@ public interface StatusBarPhoneModule { wakefulnessLifecycle, statusBarStateController, vibratorHelper, - bubbleController, + bubblesOptional, visualStabilityManager, deviceProvisionedController, navigationBarController, diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index ae96829379e9..bf9df8e2f89e 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -24,6 +24,7 @@ import android.util.DisplayMetrics; import android.view.IWindowManager; import com.android.internal.logging.UiEventLogger; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.pip.Pip; @@ -148,5 +149,8 @@ public abstract class WMShellBaseModule { abstract SplitScreen optionalSplitScreen(); @BindsOptionalOf + abstract Bubbles optionalBubbles(); + + @BindsOptionalOf abstract OneHanded optionalOneHanded(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 3b8f1bb54d79..2f8d3f6a0722 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -1011,6 +1011,29 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mNotificationGroupManager, times(1)).onEntryRemoved(groupSummary.getEntry()); } + + /** + * Verifies that when a non visually interruptive update occurs for a bubble in the overflow, + * the that bubble does not get promoted from the overflow. + */ + @Test + public void test_notVisuallyInterruptive_updateOverflowBubble_notAdded() { + // Setup + mBubbleController.updateBubble(mRow.getEntry()); + mBubbleController.updateBubble(mRow2.getEntry()); + assertTrue(mBubbleController.hasBubbles()); + + // Overflow it + mBubbleData.dismissBubbleWithKey(mRow.getEntry().getKey(), + BubbleController.DISMISS_USER_GESTURE); + assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse(); + assertThat(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())).isTrue(); + + // Test + mBubbleController.updateBubble(mRow.getEntry()); + assertThat(mBubbleData.hasBubbleInStackWithKey(mRow.getEntry().getKey())).isFalse(); + } + /** * Sets the bubble metadata flags for this entry. These ]flags are normally set by * NotificationManagerService when the notification is sent, however, these tests do not diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java index 315caeebe0e9..4bbc41e517b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java @@ -513,6 +513,26 @@ public class BubbleDataTest extends SysuiTestCase { } /** + * Verifies that when a non visually interruptive update occurs, that the selection does not + * change. + */ + @Test + public void test_notVisuallyInterruptive_updateBubble_selectionDoesntChange() { + // Setup + sendUpdatedEntryAtTime(mEntryA1, 1000); + sendUpdatedEntryAtTime(mEntryB1, 2000); + sendUpdatedEntryAtTime(mEntryB2, 3000); + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] + mBubbleData.setListener(mListener); + + assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA2); + + // Test + sendUpdatedEntryAtTime(mEntryB1, 5000, false /* isVisuallyInterruptive */); + assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA2); + } + + /** * Verifies that a request to expand the stack has no effect if there are no bubbles. */ @Test @@ -883,9 +903,15 @@ public class BubbleDataTest extends SysuiTestCase { } private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) { + sendUpdatedEntryAtTime(entry, postTime, true /* visuallyInterruptive */); + } + + private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime, + boolean visuallyInterruptive) { setPostTime(entry, postTime); // BubbleController calls this: Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */); + b.setVisuallyInterruptiveForTest(visuallyInterruptive); // And then this mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/, true /* showInShade */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 8a30b00e609d..81139f192070 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -43,7 +43,6 @@ import com.android.systemui.statusbar.phone.KeyguardDismissUtil import com.android.systemui.util.animation.TransitionLayout import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.any import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import dagger.Lazy @@ -53,7 +52,6 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mock import org.mockito.Mockito.anyBoolean @@ -203,7 +201,7 @@ public class MediaControlPanelTest : SysuiTestCase() { fun bindWhenUnattached() { val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, null, null, device, true, null) - player.bind(state) + player.bind(state, PACKAGE) assertThat(player.isPlaying()).isFalse() } @@ -212,7 +210,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state) + player.bind(state, PACKAGE) assertThat(appName.getText()).isEqualTo(APP) assertThat(titleText.getText()).isEqualTo(TITLE) assertThat(artistText.getText()).isEqualTo(ARTIST) @@ -223,7 +221,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state) + player.bind(state, PACKAGE) val list = ArgumentCaptor.forClass(ColorStateList::class.java) verify(view).setBackgroundTintList(list.capture()) assertThat(list.value).isEqualTo(ColorStateList.valueOf(BG_COLOR)) @@ -234,7 +232,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state) + player.bind(state, PACKAGE) assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME) assertThat(seamless.isEnabled()).isTrue() } @@ -246,7 +244,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null) - player.bind(state) + player.bind(state, PACKAGE) verify(expandedSet).setVisibility(seamless.id, View.GONE) verify(expandedSet).setVisibility(seamlessFallback.id, View.VISIBLE) verify(collapsedSet).setVisibility(seamless.id, View.GONE) @@ -258,7 +256,7 @@ public class MediaControlPanelTest : SysuiTestCase() { player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null) - player.bind(state) + player.bind(state, PACKAGE) assertThat(seamless.isEnabled()).isTrue() assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString( com.android.internal.R.string.ext_media_seamless_action)) @@ -270,7 +268,7 @@ public class MediaControlPanelTest : SysuiTestCase() { val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null, resumption = true) - player.bind(state) + player.bind(state, PACKAGE) assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME) assertThat(seamless.isEnabled()).isFalse() } @@ -322,31 +320,18 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun dismissButtonClick() { + val mediaKey = "key for dismissal" player.attach(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null, notificationKey = KEY) - player.bind(state) + player.bind(state, mediaKey) dismiss.callOnClick() val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java) verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean()) captor.value.onDismiss() - verify(mediaDataManager).dismissMediaData(eq(KEY), anyLong()) - } - - @Test - fun dismissButtonClick_nullNotificationKey() { - player.attach(holder) - val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), - emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null) - player.bind(state) - - verify(keyguardDismissUtil, never()) - .executeWhenUnlocked( - any(ActivityStarter.OnDismissAction::class.java), - ArgumentMatchers.anyBoolean() - ) + verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong()) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java index 3f10c8da576b..9b6dd05cd80c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/buttons/KeyButtonViewTest.java @@ -53,8 +53,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.navigationbar.buttons.KeyButtonView; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.recents.OverviewProxyService; import org.junit.Before; @@ -71,7 +70,7 @@ public class KeyButtonViewTest extends SysuiTestCase { private KeyButtonView mKeyButtonView; private MetricsLogger mMetricsLogger; - private BubbleController mBubbleController; + private Bubbles mBubbles; private UiEventLogger mUiEventLogger; private InputManager mInputManager = mock(InputManager.class); @Captor @@ -81,7 +80,7 @@ public class KeyButtonViewTest extends SysuiTestCase { public void setup() throws Exception { MockitoAnnotations.initMocks(this); mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); - mBubbleController = mDependency.injectMockDependency(BubbleController.class); + mBubbles = mDependency.injectMockDependency(Bubbles.class); mDependency.injectMockDependency(OverviewProxyService.class); mUiEventLogger = mDependency.injectMockDependency(UiEventLogger.class); @@ -155,7 +154,7 @@ public class KeyButtonViewTest extends SysuiTestCase { @Test public void testBubbleEvents_bubbleExpanded() { - when(mBubbleController.getExpandedDisplayId(mContext)).thenReturn(3); + when(mBubbles.getExpandedDisplayId(mContext)).thenReturn(3); int action = KeyEvent.ACTION_DOWN; int flags = 0; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java index 5d14898cdd2c..faf43a21356e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java @@ -43,6 +43,7 @@ import com.android.systemui.qs.QSTileHost; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; +import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; @@ -73,12 +74,16 @@ public class CastTileTest extends SysuiTestCase { @Mock private QSTileHost mHost; @Mock - NetworkController.SignalCallback mCallback; + NetworkController.SignalCallback mSignalCallback; @Mock private MetricsLogger mMetricsLogger; @Mock private StatusBarStateController mStatusBarStateController; @Mock + private HotspotController mHotspotController; + @Mock + private HotspotController.Callback mHotspotCallback; + @Mock private QSLogger mQSLogger; private TestableLooper mTestableLooper; @@ -101,7 +106,8 @@ public class CastTileTest extends SysuiTestCase { mQSLogger, mController, mKeyguard, - mNetworkController + mNetworkController, + mHotspotController ); // We are not setting the mocks to listening, so we trigger a first refresh state to @@ -113,14 +119,22 @@ public class CastTileTest extends SysuiTestCase { ArgumentCaptor.forClass(NetworkController.SignalCallback.class); verify(mNetworkController).observe(any(LifecycleOwner.class), signalCallbackArgumentCaptor.capture()); - mCallback = signalCallbackArgumentCaptor.getValue(); + mSignalCallback = signalCallbackArgumentCaptor.getValue(); + + ArgumentCaptor<HotspotController.Callback> hotspotCallbackArgumentCaptor = + ArgumentCaptor.forClass(HotspotController.Callback.class); + verify(mHotspotController).observe(any(LifecycleOwner.class), + hotspotCallbackArgumentCaptor.capture()); + mHotspotCallback = hotspotCallbackArgumentCaptor.getValue(); } + // ------------------------------------------------- + // All these tests for enabled/disabled wifi have hotspot not enabled @Test public void testStateUnavailable_wifiDisabled() { NetworkController.IconState qsIcon = new NetworkController.IconState(false, 0, ""); - mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class), + mSignalCallback.setWifiIndicators(false, mock(NetworkController.IconState.class), qsIcon, false,false, "", false, ""); mTestableLooper.processAllMessages(); @@ -132,7 +146,7 @@ public class CastTileTest extends SysuiTestCase { public void testStateUnavailable_wifiNotConnected() { NetworkController.IconState qsIcon = new NetworkController.IconState(false, 0, ""); - mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class), + mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class), qsIcon, false,false, "", false, ""); mTestableLooper.processAllMessages(); @@ -143,7 +157,7 @@ public class CastTileTest extends SysuiTestCase { private void enableWifiAndProcessMessages() { NetworkController.IconState qsIcon = new NetworkController.IconState(true, 0, ""); - mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class), + mSignalCallback.setWifiIndicators(true, mock(NetworkController.IconState.class), qsIcon, false,false, "", false, ""); mTestableLooper.processAllMessages(); @@ -166,6 +180,46 @@ public class CastTileTest extends SysuiTestCase { enableWifiAndProcessMessages(); assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state); } + // ------------------------------------------------- + + // ------------------------------------------------- + // All these tests for enabled/disabled hotspot have wifi not enabled + @Test + public void testStateUnavailable_hotspotDisabled() { + mHotspotCallback.onHotspotChanged(false, 0); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state); + } + + @Test + public void testStateUnavailable_hotspotEnabledNotConnected() { + mHotspotCallback.onHotspotChanged(true, 0); + mTestableLooper.processAllMessages(); + + assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state); + } + + @Test + public void testStateActive_hotspotEnabledAndConnectedAndCasting() { + CastController.CastDevice device = new CastController.CastDevice(); + device.state = CastController.CastDevice.STATE_CONNECTED; + List<CastDevice> devices = new ArrayList<>(); + devices.add(device); + when(mController.getCastDevices()).thenReturn(devices); + + mHotspotCallback.onHotspotChanged(true, 1); + mTestableLooper.processAllMessages(); + assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state); + } + + @Test + public void testStateInactive_hotspotEnabledAndConnectedAndNotCasting() { + mHotspotCallback.onHotspotChanged(true, 1); + mTestableLooper.processAllMessages(); + assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state); + } + // ------------------------------------------------- @Test public void testHandleClick_castDevicePresent() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index d041ee047ae0..10eca00feec4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -36,7 +36,7 @@ import android.widget.LinearLayout; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper; import com.android.systemui.statusbar.notification.AssistantFeedbackController; import com.android.systemui.statusbar.notification.DynamicChildBindController; @@ -65,6 +65,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.Spy; import java.util.List; +import java.util.Optional; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -106,7 +107,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager, mock(StatusBarStateControllerImpl.class), mEntryManager, mock(KeyguardBypassController.class), - mock(BubbleController.class), + Optional.of(mock(Bubbles.class)), mock(DynamicPrivacyController.class), mock(ForegroundServiceSectionController.class), mock(DynamicChildBindController.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index dfe006dfd4fe..d835123e4cad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -42,6 +42,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.ForegroundServiceController; import com.android.systemui.SysuiTestCase; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -61,6 +62,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -112,7 +115,8 @@ public class NotificationFilterTest extends SysuiTestCase { mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), - () -> mock(PeopleNotificationIdentifier.class))); + () -> mock(PeopleNotificationIdentifier.class), + Optional.of(() -> mock(Bubbles.class)))); mDependency.injectMockDependency(ShadeController.class); mDependency.injectMockDependency(NotificationLockscreenUserManager.class); mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java index edb8776bcb02..b20f95cfad3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java @@ -46,7 +46,6 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; @@ -78,7 +77,6 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { public void setUp() { allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(BubbleController.class); when(mGutsManager.openGuts( any(View.class), anyInt(), @@ -86,7 +84,6 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { any(NotificationMenuRowPlugin.MenuItem.class))) .thenReturn(true); when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem); - mDependency.injectMockDependency(BubbleController.class); mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java index 3c5aa1ae9519..9465a3db00ac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java @@ -76,7 +76,7 @@ import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.bubbles.BubblesTestActivity; import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -97,6 +97,7 @@ import org.mockito.stubbing.Answer; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import javax.inject.Provider; @@ -136,7 +137,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { @Mock private OnUserInteractionCallback mOnUserInteractionCallback; @Mock - private BubbleController mBubbleController; + private Bubbles mBubbles; @Mock private LauncherApps mLauncherApps; @Mock @@ -161,7 +162,6 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mTestHandler = new Handler(mTestableLooper.getLooper()); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); - mDependency.injectTestDependency(BubbleController.class, mBubbleController); mDependency.injectTestDependency(ShadeController.class, mShadeController); // Inflate the layout final LayoutInflater layoutInflater = LayoutInflater.from(mContext); @@ -255,7 +255,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon); assertEquals(mIconDrawable, view.getDrawable()); } @@ -279,7 +279,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name); assertTrue(textView.getText().toString().contains("App Name")); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -330,7 +330,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertTrue(textView.getText().toString().contains(group.getName())); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -355,7 +355,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); assertEquals(GONE, textView.getVisibility()); @@ -379,7 +379,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(GONE, nameView.getVisibility()); } @@ -414,7 +414,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(VISIBLE, nameView.getVisibility()); assertTrue(nameView.getText().toString().contains("Proxied")); @@ -442,7 +442,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final View settingsButton = mNotificationInfo.findViewById(R.id.info); settingsButton.performClick(); @@ -468,7 +468,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -495,7 +495,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, false, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -520,7 +520,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View view = mNotificationInfo.findViewById(R.id.silence); assertThat(view.isSelected()).isTrue(); } @@ -548,7 +548,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo( @@ -579,7 +579,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo( @@ -609,7 +609,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -653,7 +653,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mTestableLooper.processAllMessages(); @@ -696,7 +696,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View silence = mNotificationInfo.findViewById(R.id.silence); @@ -740,7 +740,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -777,7 +777,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -813,7 +813,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -851,7 +851,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -887,7 +887,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -923,7 +923,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -958,7 +958,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); View silence = mNotificationInfo.findViewById(R.id.silence); silence.performClick(); @@ -992,7 +992,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage( anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID)); @@ -1017,7 +1017,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mBuilderProvider, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage( anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID)); @@ -1052,7 +1052,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { () -> b, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); // WHEN user clicks "priority" mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); @@ -1092,7 +1092,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase { () -> b, true, mTestHandler, - mTestHandler, null, mBubbleController); + mTestHandler, null, Optional.of(mBubbles)); // WHEN user clicks "priority" mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index e1668cab3333..bbc1df21237f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -67,7 +67,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.settings.UserContextProvider; import com.android.systemui.statusbar.NotificationLockscreenUserManager; @@ -93,6 +93,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Optional; + import javax.inject.Provider; /** @@ -129,7 +131,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Mock private ChannelEditorDialogController mChannelEditorDialogController; @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; @Mock private UserContextProvider mContextTracker; - @Mock private BubbleController mBubbleController; + @Mock private Bubbles mBubbles; @Mock(answer = Answers.RETURNS_SELF) private PriorityOnboardingDialogController.Builder mBuilder; private Provider<PriorityOnboardingDialogController.Builder> mProvider = () -> mBuilder; @@ -145,7 +147,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { mDependency.injectTestDependency( OnUserInteractionCallback.class, mOnUserInteractionCallback); - mDependency.injectTestDependency(BubbleController.class, mBubbleController); mDependency.injectMockDependency(NotificationLockscreenUserManager.class); mHandler = Handler.createAsync(mTestableLooper.getLooper()); mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this)); @@ -155,7 +156,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { () -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider, mINotificationManager, mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, mProvider, - mAssistantFeedbackController, mBubbleController, + mAssistantFeedbackController, Optional.of(mBubbles), new UiEventLoggerFake(), mOnUserInteractionCallback); mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer, mCheckSaveListener, mOnSettingsClickListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java index b952c056c33d..2ce8b34b193a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java @@ -45,7 +45,7 @@ import android.widget.RemoteViews; import com.android.systemui.R; import com.android.systemui.TestableDependency; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.bubbles.BubblesTestActivity; import com.android.systemui.media.MediaFeatureFlag; import com.android.systemui.plugins.FalsingManager; @@ -73,6 +73,7 @@ import com.android.systemui.statusbar.policy.SmartReplyConstants; import org.mockito.ArgumentCaptor; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -114,12 +115,12 @@ public class NotificationTestHelper { mContext = context; mTestLooper = testLooper; dependency.injectMockDependency(NotificationMediaManager.class); - dependency.injectMockDependency(BubbleController.class); dependency.injectMockDependency(NotificationShadeWindowController.class); mStatusBarStateController = mock(StatusBarStateController.class); mGroupMembershipManager = new NotificationGroupManagerLegacy( mStatusBarStateController, - () -> mock(PeopleNotificationIdentifier.class)); + () -> mock(PeopleNotificationIdentifier.class), + Optional.of(() -> mock(Bubbles.class))); mGroupExpansionManager = mGroupMembershipManager; mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController, mock(KeyguardBypassController.class), mock(NotificationGroupManagerLegacy.class), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java index 57020eb08a7f..83b6d2c088b9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java @@ -29,7 +29,6 @@ import android.view.View; import androidx.test.filters.SmallTest; -import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.AlertingNotificationManager; import com.android.systemui.statusbar.AlertingNotificationManagerTest; @@ -95,7 +94,6 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest { when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt())) .thenReturn(TEST_AUTO_DISMISS_TIME); when(mVSManager.isReorderingAllowed()).thenReturn(true); - mDependency.injectMockDependency(BubbleController.class); mDependency.injectMockDependency(NotificationShadeWindowController.class); mDependency.injectMockDependency(ConfigurationController.class); mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mGroupManager, mVSManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java index 2ece8be8d332..7d84f86cc7b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java @@ -37,7 +37,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -61,6 +61,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.HashMap; +import java.util.Optional; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -83,7 +84,6 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(BubbleController.class); mHeadsUpManager = new HeadsUpManager(mContext) {}; when(mNotificationEntryManager.getPendingNotificationsIterator()) @@ -91,7 +91,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase { mGroupManager = new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), - () -> mock(PeopleNotificationIdentifier.class)); + () -> mock(PeopleNotificationIdentifier.class), + Optional.of(() -> mock(Bubbles.class))); mDependency.injectTestDependency(NotificationGroupManagerLegacy.class, mGroupManager); mGroupManager.setHeadsUpManager(mHeadsUpManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java index 0aa009134440..29e445a13e24 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java @@ -30,7 +30,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy; @@ -45,6 +45,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.Optional; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -60,14 +62,15 @@ public class NotificationGroupManagerLegacyTest extends SysuiTestCase { @Before public void setup() { - mDependency.injectMockDependency(BubbleController.class); + mDependency.injectMockDependency(Bubbles.class); initializeGroupManager(); } private void initializeGroupManager() { mGroupManager = new NotificationGroupManagerLegacy( mock(StatusBarStateController.class), - () -> mock(PeopleNotificationIdentifier.class)); + () -> mock(PeopleNotificationIdentifier.class), + Optional.of(() -> mock(Bubbles.class))); mGroupManager.setHeadsUpManager(mHeadsUpManager); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java index 5222ffff2637..ede5fceb4ebd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java @@ -26,7 +26,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -41,6 +41,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -66,7 +68,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { StatusBarWindowController mStatusBarWindowController; private NotificationIconAreaController mController; @Mock - private BubbleController mBubbleController; + private Bubbles mBubbles; @Mock private DemoModeController mDemoModeController; @Mock private NotificationIconContainer mAodIcons; @@ -83,7 +85,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase { mNotificationMediaManager, mListener, mDozeParameters, - mBubbleController, + Optional.of(mBubbles), mDemoModeController, mDarkIconDispatcher, mStatusBarWindowController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 792637d8479b..f7489b1c164a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -53,7 +53,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -86,6 +86,7 @@ import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import java.util.ArrayList; +import java.util.Optional; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -115,7 +116,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private Handler mHandler; @Mock - private BubbleController mBubbleController; + private Bubbles mBubbles; @Mock private ShadeControllerImpl mShadeController; @Mock @@ -192,7 +193,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mock(KeyguardManager.class), mock(IDreamManager.class), - mBubbleController, + Optional.of(mBubbles), () -> mAssistManager, mRemoteInputManager, mock(NotificationGroupManagerLegacy.class), @@ -279,7 +280,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry())); + verify(mBubbles).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry())); // This is called regardless, and simply short circuits when there is nothing to do. verify(mShadeController, atLeastOnce()).collapsePanel(); @@ -311,7 +312,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); + verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); verify(mShadeController, atLeastOnce()).collapsePanel(); @@ -341,7 +342,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); + verify(mBubbles).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); verify(mShadeController, atLeastOnce()).collapsePanel(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 7d8a62607395..23b12d4e115f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -80,7 +80,7 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.bubbles.Bubbles; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.demomode.DemoModeController; @@ -219,7 +219,7 @@ public class StatusBarTest extends SysuiTestCase { @Mock private UserSwitcherController mUserSwitcherController; @Mock private NetworkController mNetworkController; @Mock private VibratorHelper mVibratorHelper; - @Mock private BubbleController mBubbleController; + @Mock private Bubbles mBubbles; @Mock private NotificationShadeWindowController mNotificationShadeWindowController; @Mock private NotificationIconAreaController mNotificationIconAreaController; @Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController; @@ -332,7 +332,7 @@ public class StatusBarTest extends SysuiTestCase { mShadeController = new ShadeControllerImpl(mCommandQueue, mStatusBarStateController, mNotificationShadeWindowController, mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class), - () -> mStatusBar, () -> mAssistManager, () -> mBubbleController); + () -> mStatusBar, () -> mAssistManager, Optional.of(() -> mBubbles)); mStatusBar = new StatusBar( mContext, @@ -374,7 +374,7 @@ public class StatusBarTest extends SysuiTestCase { wakefulnessLifecycle, mStatusBarStateController, mVibratorHelper, - mBubbleController, + Optional.of(mBubbles), mVisualStabilityManager, mDeviceProvisionedController, mNavigationBarController, diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 8099f8f37bc7..e67b9d8ccd91 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -2,8 +2,7 @@ per-file ConnectivityService.java,NetworkManagementService.java,NsdService.java = codewiz@google.com, ek@google.com, jchalard@google.com, junyulai@google.com, lorenzo@google.com, reminv@google.com, satk@google.com # Vibrator / Threads -per-file VibratorService.java, DisplayThread.java = michaelwr@google.com -per-file VibratorService.java, DisplayThread.java = ogunwale@google.com +per-file VibratorManagerService.java, VibratorService.java, DisplayThread.java = michaelwr@google.com, ogunwale@google.com # Zram writeback per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com diff --git a/services/core/java/com/android/server/VibratorManagerService.java b/services/core/java/com/android/server/VibratorManagerService.java new file mode 100644 index 000000000000..2f35da79420e --- /dev/null +++ b/services/core/java/com/android/server/VibratorManagerService.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.os.IBinder; +import android.os.IVibratorManagerService; +import android.os.ResultReceiver; +import android.os.ShellCallback; +import android.os.ShellCommand; + +import com.android.internal.annotations.VisibleForTesting; + +import libcore.util.NativeAllocationRegistry; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Arrays; + +/** System implementation of {@link IVibratorManagerService}. */ +public class VibratorManagerService extends IVibratorManagerService.Stub { + private static final String TAG = "VibratorManagerService"; + private static final boolean DEBUG = false; + + private final Context mContext; + private final NativeWrapper mNativeWrapper; + private final int[] mVibratorIds; + + static native long nativeInit(); + + static native long nativeGetFinalizer(); + + static native int[] nativeGetVibratorIds(long nativeServicePtr); + + VibratorManagerService(Context context) { + this(context, new Injector()); + } + + @VisibleForTesting + VibratorManagerService(Context context, Injector injector) { + mContext = context; + mNativeWrapper = injector.getNativeWrapper(); + + mNativeWrapper.init(); + + int[] vibratorIds = mNativeWrapper.getVibratorIds(); + mVibratorIds = vibratorIds == null ? new int[0] : vibratorIds; + } + + @Override // Binder call + public int[] getVibratorIds() { + return Arrays.copyOf(mVibratorIds, mVibratorIds.length); + } + + @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback cb, ResultReceiver resultReceiver) { + new VibratorManagerShellCommand(this).exec(this, in, out, err, args, cb, resultReceiver); + } + + /** Point of injection for test dependencies */ + @VisibleForTesting + static class Injector { + + NativeWrapper getNativeWrapper() { + return new NativeWrapper(); + } + } + + /** Wrapper around the static-native methods of {@link VibratorManagerService} for tests. */ + @VisibleForTesting + public static class NativeWrapper { + + private long mNativeServicePtr = 0; + + /** Returns native pointer to newly created controller and connects with HAL service. */ + public void init() { + mNativeServicePtr = VibratorManagerService.nativeInit(); + long finalizerPtr = VibratorManagerService.nativeGetFinalizer(); + + if (finalizerPtr != 0) { + NativeAllocationRegistry registry = + NativeAllocationRegistry.createMalloced( + VibratorManagerService.class.getClassLoader(), finalizerPtr); + registry.registerNativeAllocation(this, mNativeServicePtr); + } + } + + /** Returns vibrator ids. */ + public int[] getVibratorIds() { + return VibratorManagerService.nativeGetVibratorIds(mNativeServicePtr); + } + } + + /** Provides limited functionality from {@link VibratorManagerService} as shell commands. */ + private final class VibratorManagerShellCommand extends ShellCommand { + + private final IBinder mToken; + + private VibratorManagerShellCommand(IBinder token) { + mToken = token; + } + + @Override + public int onCommand(String cmd) { + if ("list".equals(cmd)) { + return runListVibrators(); + } + return handleDefaultCommands(cmd); + } + + private int runListVibrators() { + try (PrintWriter pw = getOutPrintWriter();) { + if (mVibratorIds.length == 0) { + pw.println("No vibrator found"); + } else { + for (int id : mVibratorIds) { + pw.println(id); + } + } + pw.println(""); + return 0; + } + } + + @Override + public void onHelp() { + try (PrintWriter pw = getOutPrintWriter();) { + pw.println("Vibrator Manager commands:"); + pw.println(" help"); + pw.println(" Prints this help text."); + pw.println(""); + pw.println(" list"); + pw.println(" Prints the id of device vibrators. This do not include any "); + pw.println(" connected input device."); + pw.println(""); + } + } + } +} diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 687af107590a..cb6f616f5078 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -385,15 +385,7 @@ public class VibratorService extends IVibratorService.Stub mNativeWrapper = injector.getNativeWrapper(); mH = injector.createHandler(Looper.myLooper()); - long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete); - long finalizerPtr = mNativeWrapper.vibratorGetFinalizer(); - - if (finalizerPtr != 0) { - NativeAllocationRegistry registry = - NativeAllocationRegistry.createMalloced( - VibratorService.class.getClassLoader(), finalizerPtr); - registry.registerNativeAllocation(this, nativeServicePtr); - } + mNativeWrapper.vibratorInit(this::onVibrationComplete); // Reset the hardware to a default state, in case this is a runtime // restart instead of a fresh boot. @@ -1746,18 +1738,17 @@ public class VibratorService extends IVibratorService.Stub return VibratorService.vibratorExists(mNativeServicePtr); } - /** - * Returns native pointer to newly created controller and initializes connection to vibrator - * HAL service. - */ - public long vibratorInit(OnCompleteListener listener) { + /** Initializes connection to vibrator HAL service. */ + public void vibratorInit(OnCompleteListener listener) { mNativeServicePtr = VibratorService.vibratorInit(listener); - return mNativeServicePtr; - } + long finalizerPtr = VibratorService.vibratorGetFinalizer(); - /** Returns pointer to native finalizer function to be called by GC. */ - public long vibratorGetFinalizer() { - return VibratorService.vibratorGetFinalizer(); + if (finalizerPtr != 0) { + NativeAllocationRegistry registry = + NativeAllocationRegistry.createMalloced( + VibratorService.class.getClassLoader(), finalizerPtr); + registry.registerNativeAllocation(this, mNativeServicePtr); + } } /** Turns vibrator on for given time. */ diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c0f6011a45cd..91a3fb003df2 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -478,15 +478,15 @@ public final class ActiveServices { } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, - int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification, - String callingPackage, @Nullable String callingFeatureId, final int userId) + int callingPid, int callingUid, boolean fgRequired, String callingPackage, + @Nullable String callingFeatureId, final int userId) throws TransactionTooLargeException { return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired, - hideFgNotification, callingPackage, callingFeatureId, userId, false, null); + callingPackage, callingFeatureId, userId, false, null); } ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, - int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification, + int callingPid, int callingUid, boolean fgRequired, String callingPackage, @Nullable String callingFeatureId, final int userId, boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException { @@ -653,7 +653,6 @@ public final class ActiveServices { r.startRequested = true; r.delayedStop = false; r.fgRequired = fgRequired; - r.hideFgNotification = hideFgNotification; r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants, callingUid)); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ef75264b4c00..4f056df4dff9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1177,10 +1177,6 @@ public class ActivityManagerService extends IActivityManager.Stub final Injector mInjector; - /** The package verifier app. */ - private String mPackageVerifier; - private int mPackageVerifierUid = UserHandle.USER_NULL; - static final class ProcessChangeItem { static final int CHANGE_ACTIVITIES = 1<<0; static final int CHANGE_FOREGROUND_SERVICES = 1<<1; @@ -1809,18 +1805,6 @@ public class ActivityManagerService extends IActivityManager.Stub if (phase == PHASE_SYSTEM_SERVICES_READY) { mService.mBatteryStatsService.systemServicesReady(); mService.mServices.systemServicesReady(); - mService.mPackageVerifier = ArrayUtils.firstOrNull( - LocalServices.getService(PackageManagerInternal.class).getKnownPackageNames( - PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM)); - if (mService.mPackageVerifier != null) { - try { - mService.mPackageVerifierUid = - getContext().getPackageManager().getPackageUid( - mService.mPackageVerifier, UserHandle.USER_SYSTEM); - } catch (NameNotFoundException e) { - Slog.wtf(TAG, "Package manager couldn't get package verifier uid", e); - } - } } else if (phase == PHASE_ACTIVITY_MANAGER_READY) { mService.startBroadcastObservers(); } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { @@ -8269,7 +8253,7 @@ public class ActivityManagerService extends IActivityManager.Stub private void dumpEverything(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage, boolean dumpClient, boolean dumpNormalPriority, - int dumpAppId) { + int dumpAppId, boolean dumpProxies) { ActiveServices.ServiceDumper sdumper; @@ -8328,7 +8312,7 @@ public class ActivityManagerService extends IActivityManager.Stub } sdumper.dumpWithClient(); } - if (dumpPackage == null) { + if (dumpPackage == null && dumpProxies) { // Intentionally dropping the lock for this, because dumpBinderProxies() will make many // outgoing binder calls to retrieve interface descriptors; while that is system code, // there is nothing preventing an app from overriding this implementation by talking to @@ -8737,13 +8721,14 @@ public class ActivityManagerService extends IActivityManager.Stub // dumpEverything() will take the lock when needed, and momentarily drop // it for dumping client state. dumpEverything(fd, pw, args, opti, dumpAll, dumpPackage, dumpClient, - dumpNormalPriority, dumpAppId); + dumpNormalPriority, dumpAppId, true /* dumpProxies */); } else { // Take the lock here, so we get a consistent state for the entire dump; - // dumpEverything() will take the lock as well, but that is fine. + // dumpEverything() will take the lock as well, which is fine for everything + // except dumping proxies, which can take a long time; exclude them. synchronized(this) { dumpEverything(fd, pw, args, opti, dumpAll, dumpPackage, dumpClient, - dumpNormalPriority, dumpAppId); + dumpNormalPriority, dumpAppId, false /* dumpProxies */); } } } @@ -12359,8 +12344,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public ComponentName startService(IApplicationThread caller, Intent service, - String resolvedType, boolean requireForeground, boolean hideForegroundNotification, - String callingPackage, String callingFeatureId, int userId) + String resolvedType, boolean requireForeground, String callingPackage, + String callingFeatureId, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors @@ -12372,27 +12357,17 @@ public class ActivityManagerService extends IActivityManager.Stub throw new IllegalArgumentException("callingPackage cannot be null"); } - final int callingUid = Binder.getCallingUid(); - if (requireForeground && hideForegroundNotification) { - if (!UserHandle.isSameApp(callingUid, mPackageVerifierUid) - || !callingPackage.equals(mPackageVerifier)) { - throw new IllegalArgumentException( - "Only the package verifier can hide its foreground service notification"); - } - Slog.i(TAG, "Foreground service notification hiding requested by " + callingPackage); - } - if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground); synchronized(this) { final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res; try { res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, - requireForeground, hideForegroundNotification, - callingPackage, callingFeatureId, userId); + requireForeground, callingPackage, callingFeatureId, userId); } finally { Binder.restoreCallingIdentity(origId); } @@ -16305,7 +16280,7 @@ public class ActivityManagerService extends IActivityManager.Stub ComponentName res; try { res = mServices.startServiceLocked(null, service, - resolvedType, -1, uid, fgRequired, false, callingPackage, + resolvedType, -1, uid, fgRequired, callingPackage, callingFeatureId, userId, allowBackgroundActivityStarts, backgroundActivityStartsToken); } finally { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 11197287114c..d346430fe312 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -655,7 +655,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println("Starting service: " + intent); pw.flush(); ComponentName cn = mInterface.startService(null, intent, intent.getType(), - asForeground, false, SHELL_PACKAGE_NAME, null, mUserId); + asForeground, SHELL_PACKAGE_NAME, null, mUserId); if (cn == null) { err.println("Error: Not found; no service started."); return -1; diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index a7d8ca496f75..4cdf66130cf4 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -105,7 +105,6 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN boolean whitelistManager; // any bindings to this service have BIND_ALLOW_WHITELIST_MANAGEMENT? boolean delayed; // are we waiting to start this service in the background? boolean fgRequired; // is the service required to go foreground after starting? - boolean hideFgNotification; // Hide the fg service notification boolean fgWaiting; // is a timeout for going foreground already scheduled? boolean isForeground; // is service currently in foreground mode? int foregroundId; // Notification ID of last foreground req. @@ -886,9 +885,6 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } public void postNotification() { - if (hideFgNotification) { - return; - } final int appUid = appInfo.uid; final int appPid = app.pid; if (foregroundId != 0 && foregroundNoti != null) { diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java index 6e6ec747e24e..c17bc917071c 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java @@ -61,7 +61,6 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; import com.android.server.biometrics.sensors.PerformanceTracker; import com.android.server.biometrics.sensors.RemovalConsumer; -import com.android.server.biometrics.sensors.fingerprint.FingerprintUpdateActiveUserClient; import org.json.JSONArray; import org.json.JSONException; @@ -404,7 +403,7 @@ class Face10 implements IHwBinder.DeathRecipient { } /** - * Schedules the {@link FingerprintUpdateActiveUserClient} without posting the work onto the + * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser" * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule * this operation on the same lambda/runnable as those operations so that the ordering is diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java index 2f0e56447e20..2903b9970033 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java @@ -57,6 +57,8 @@ import com.android.server.biometrics.Utils; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; +import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21; +import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index 507b5dd3f224..c87bfec85dc3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.annotation.Nullable; @@ -64,6 +64,8 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; import com.android.server.biometrics.sensors.PerformanceTracker; import com.android.server.biometrics.sensors.RemovalConsumer; +import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; +import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import org.json.JSONArray; import org.json.JSONException; @@ -81,7 +83,7 @@ import java.util.Map; * Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or * its extended minor versions. */ -class Fingerprint21 implements IHwBinder.DeathRecipient { +public class Fingerprint21 implements IHwBinder.DeathRecipient { private static final String TAG = "Fingerprint21"; private static final int ENROLL_TIMEOUT_SEC = 60; @@ -349,7 +351,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { sensorType, resetLockoutRequiresHardwareAuthToken); } - static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength, + public static Fingerprint21 newInstance(@NonNull Context context, int sensorId, int strength, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { final Handler handler = new Handler(Looper.getMainLooper()); @@ -433,7 +435,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { @Nullable IUdfpsOverlayController getUdfpsOverlayController() { return mUdfpsOverlayController; } - @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) { + @LockoutTracker.LockoutMode public int getLockoutModeForUser(int userId) { return mLockoutTracker.getLockoutModeForUser(userId); } @@ -479,7 +481,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void scheduleResetLockout(int userId) { + public void scheduleResetLockout(int userId) { // Fingerprint2.1 keeps track of lockout in the framework. Let's just do it on the handler // thread. mHandler.post(() -> { @@ -487,7 +489,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void scheduleGenerateChallenge(@NonNull IBinder token, + public void scheduleGenerateChallenge(@NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName) { mHandler.post(() -> { final FingerprintGenerateChallengeClient client = @@ -498,7 +500,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String opPackageName) { + public void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String opPackageName) { mHandler.post(() -> { final FingerprintRevokeChallengeClient client = new FingerprintRevokeChallengeClient( mContext, mLazyDaemon, token, opPackageName, mSensorProperties.sensorId); @@ -506,7 +508,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, + public void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName, @Nullable Surface surface) { mHandler.post(() -> { @@ -529,13 +531,13 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void cancelEnrollment(@NonNull IBinder token) { + public void cancelEnrollment(@NonNull IBinder token) { mHandler.post(() -> { mScheduler.cancelEnrollment(token); }); } - void scheduleFingerDetect(@NonNull IBinder token, int userId, + public void scheduleFingerDetect(@NonNull IBinder token, int userId, @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, @Nullable Surface surface, int statsClient) { mHandler.post(() -> { @@ -550,9 +552,10 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId, int cookie, - @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName, - boolean restricted, int statsClient, boolean isKeyguard) { + public void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId, + int cookie, @NonNull ClientMonitorCallbackConverter listener, + @NonNull String opPackageName, boolean restricted, int statsClient, + boolean isKeyguard) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -566,20 +569,21 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - void startPreparedClient(int cookie) { + public void startPreparedClient(int cookie) { mHandler.post(() -> { mScheduler.startPreparedClient(cookie); }); } - void cancelAuthentication(@NonNull IBinder token) { + public void cancelAuthentication(@NonNull IBinder token) { mHandler.post(() -> { mScheduler.cancelAuthentication(token); }); } - void scheduleRemove(@NonNull IBinder token, @NonNull IFingerprintServiceReceiver receiver, - int fingerId, int userId, @NonNull String opPackageName) { + public void scheduleRemove(@NonNull IBinder token, + @NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId, + @NonNull String opPackageName) { mHandler.post(() -> { scheduleUpdateActiveUserWithoutHandler(userId); @@ -604,30 +608,30 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { }); } - boolean isHardwareDetected() { + public boolean isHardwareDetected() { final IBiometricsFingerprint daemon = getDaemon(); return daemon != null; } - @NonNull FingerprintSensorProperties getFingerprintSensorProperties() { + @NonNull public FingerprintSensorProperties getFingerprintSensorProperties() { return mSensorProperties; } - void rename(int fingerId, int userId, String name) { + public void rename(int fingerId, int userId, String name) { mHandler.post(() -> { FingerprintUtils.getInstance().renameBiometricForUser(mContext, userId, fingerId, name); }); } - List<Fingerprint> getEnrolledFingerprints(int userId) { + public List<Fingerprint> getEnrolledFingerprints(int userId) { return FingerprintUtils.getInstance().getBiometricsForUser(mContext, userId); } - long getAuthenticatorId(int userId) { + public long getAuthenticatorId(int userId) { return mAuthenticatorIds.get(userId); } - void onFingerDown(int x, int y, float minor, float major) { + public void onFingerDown(int x, int y, float minor, float major) { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof Udfps)) { Slog.w(TAG, "onFingerDown received during client: " + client); @@ -637,7 +641,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { udfps.onFingerDown(x, y, minor, major); } - void onFingerUp() { + public void onFingerUp() { final ClientMonitor<?> client = mScheduler.getCurrentClient(); if (!(client instanceof Udfps)) { Slog.w(TAG, "onFingerDown received during client: " + client); @@ -647,11 +651,11 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { udfps.onFingerUp(); } - void setUdfpsOverlayController(IUdfpsOverlayController controller) { + public void setUdfpsOverlayController(IUdfpsOverlayController controller) { mUdfpsOverlayController = controller; } - void dumpProto(FileDescriptor fd) { + public void dumpProto(FileDescriptor fd) { PerformanceTracker tracker = PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId); @@ -691,7 +695,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient { tracker.clear(); } - void dumpInternal(@NonNull PrintWriter pw) { + public void dumpInternal(@NonNull PrintWriter pw) { PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 044dbe9664ed..6d8f241adbdc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.annotation.Nullable; @@ -43,6 +43,7 @@ import com.android.server.biometrics.sensors.BiometricScheduler; import com.android.server.biometrics.sensors.ClientMonitor; import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; import com.android.server.biometrics.sensors.LockoutResetDispatcher; +import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; import java.util.ArrayList; import java.util.Random; @@ -267,7 +268,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } } - static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId, + public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, int sensorId, @BiometricManager.Authenticators.Types int strength, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { @@ -450,12 +451,12 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage @Override @NonNull - FingerprintSensorProperties getFingerprintSensorProperties() { + public FingerprintSensorProperties getFingerprintSensorProperties() { return mSensorProperties; } @Override - void onFingerDown(int x, int y, float minor, float major) { + public void onFingerDown(int x, int y, float minor, float major) { mHandler.post(() -> { Slog.d(TAG, "onFingerDown"); final AuthenticationConsumer lastAuthenticatedConsumer = @@ -502,7 +503,7 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } @Override - void onFingerUp() { + public void onFingerUp() { mHandler.post(() -> { Slog.d(TAG, "onFingerUp"); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java index 99d348a780f3..8087e15b540d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java index 8652ee403089..5865617f4a44 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java index d5db6e411b95..1b9fae9cf91a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java index 8fb8c992268d..abaaac59fbef 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintGenerateChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintGenerateChallengeClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintInternalCleanupClient.java index 571d2b80fd3e..e0611120c69a 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalCleanupClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintInternalCleanupClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintInternalEnumerateClient.java index 834bf42eba3f..5fd1d1e812ce 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintInternalEnumerateClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintInternalEnumerateClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java index 9f5456300884..4bbb7efa2166 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRemovalClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRemovalClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRevokeChallengeClient.java index 882660e7a618..8f58cae51575 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintRevokeChallengeClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintRevokeChallengeClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java index c1c3593db564..00e2413c2f38 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.NonNull; import android.content.Context; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/LockoutFrameworkImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java index e7b2ae76f083..4fc1545c4334 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/LockoutFrameworkImpl.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/LockoutFrameworkImpl.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT; diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Udfps.java index e0806ff0fdb0..74cae02b37f4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Udfps.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; /** * Interface for under-display fingerprint sensors. diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java index 5e521d2fe46c..c71ecbf7577d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/UdfpsHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.biometrics.sensors.fingerprint; +package com.android.server.biometrics.sensors.fingerprint.hidl; import android.annotation.Nullable; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 3e619200d414..0304cdc47515 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -23,7 +23,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.ConnectivityManager; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; @@ -70,8 +69,6 @@ public class DataConnectionStats extends BroadcastReceiver { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SIM_STATE_CHANGED); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - filter.addAction(ConnectivityManager.INET_CONDITION_ACTION); mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler); } @@ -81,10 +78,7 @@ public class DataConnectionStats extends BroadcastReceiver { if (action.equals(Intent.ACTION_SIM_STATE_CHANGED)) { updateSimState(intent); notePhoneDataConnectionState(); - } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) || - action.equals(ConnectivityManager.INET_CONDITION_ACTION)) { - notePhoneDataConnectionState(); - } + } } private void notePhoneDataConnectionState() { diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java index 92dabe337d87..e28d73e8e0b9 100644 --- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java @@ -29,6 +29,7 @@ import android.util.Slog; import com.android.internal.location.timezone.LocationTimeZoneProviderRequest; +import java.time.Duration; import java.util.Objects; /** @@ -142,14 +143,13 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider { } @Override - void onEnable() { + void onEnable(@NonNull Duration initializationTimeout) { // Set a request on the proxy - it will be sent immediately if the service is bound, // or will be sent as soon as the service becomes bound. - // TODO(b/152744911): Decide whether to send a timeout so the provider knows how long - // it has to generate the first event before it could be bypassed. LocationTimeZoneProviderRequest request = new LocationTimeZoneProviderRequest.Builder() .setReportLocationTimeZone(true) + .setInitializationTimeoutMillis(initializationTimeout.toMillis()) .build(); mProxy.setRequest(request); } diff --git a/services/core/java/com/android/server/location/timezone/ControllerEnvironmentImpl.java b/services/core/java/com/android/server/location/timezone/ControllerEnvironmentImpl.java index 2e2481c30f22..b1e330668194 100644 --- a/services/core/java/com/android/server/location/timezone/ControllerEnvironmentImpl.java +++ b/services/core/java/com/android/server/location/timezone/ControllerEnvironmentImpl.java @@ -22,6 +22,7 @@ import com.android.server.LocalServices; import com.android.server.timezonedetector.ConfigurationInternal; import com.android.server.timezonedetector.TimeZoneDetectorInternal; +import java.time.Duration; import java.util.Objects; /** @@ -30,6 +31,10 @@ import java.util.Objects; */ class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Environment { + private static final Duration PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(5); + private static final Duration PROVIDER_INITIALIZATION_TIMEOUT_FUZZ = Duration.ofMinutes(1); + private static final Duration PROVIDER_UNCERTAINTY_DELAY = Duration.ofMinutes(5); + @NonNull private final TimeZoneDetectorInternal mTimeZoneDetectorInternal; @NonNull private final LocationTimeZoneProviderController mController; @@ -45,7 +50,26 @@ class ControllerEnvironmentImpl extends LocationTimeZoneProviderController.Envir } @Override + @NonNull ConfigurationInternal getCurrentUserConfigurationInternal() { return mTimeZoneDetectorInternal.getCurrentUserConfigurationInternal(); } + + @Override + @NonNull + Duration getProviderInitializationTimeout() { + return PROVIDER_INITIALIZATION_TIMEOUT; + } + + @Override + @NonNull + Duration getProviderInitializationTimeoutFuzz() { + return PROVIDER_INITIALIZATION_TIMEOUT_FUZZ; + } + + @Override + @NonNull + Duration getUncertaintyDelay() { + return PROVIDER_UNCERTAINTY_DELAY; + } } diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java index e31cfc4e8b40..bedaedacf0e3 100644 --- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java +++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java @@ -33,7 +33,6 @@ import android.location.timezone.LocationTimeZoneEvent; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.server.location.timezone.ThreadingDomain.SingleRunnableQueue; import com.android.server.timezonedetector.ConfigurationInternal; import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion; @@ -50,9 +49,6 @@ import java.util.Objects; */ class ControllerImpl extends LocationTimeZoneProviderController { - @VisibleForTesting - static final Duration UNCERTAINTY_DELAY = Duration.ofMinutes(5); - @NonNull private final LocationTimeZoneProvider mProvider; @NonNull private final SingleRunnableQueue mDelayedSuggestionQueue; @@ -140,7 +136,8 @@ class ControllerImpl extends LocationTimeZoneProviderController { switch (providerState.stateEnum) { case PROVIDER_STATE_DISABLED: { debugLog("Enabling " + mProvider); - mProvider.enable(configuration); + mProvider.enable( + configuration, mEnvironment.getProviderInitializationTimeout()); break; } case PROVIDER_STATE_ENABLED: { @@ -183,13 +180,16 @@ class ControllerImpl extends LocationTimeZoneProviderController { if (isProviderEnabled) { if (!providerWasEnabled) { // When a provider has first been enabled, we allow it some time for it to - // initialize. + // initialize before sending its first event. + Duration initializationTimeout = mEnvironment.getProviderInitializationTimeout() + .plus(mEnvironment.getProviderInitializationTimeoutFuzz()); // This sets up an empty suggestion to trigger if no explicit "certain" or - // "uncertain" suggestion preempts it within UNCERTAINTY_DELAY. If, for some reason, - // the provider does provide any events then this scheduled suggestion will ensure - // the controller makes at least an uncertain suggestion. - suggestDelayed(createEmptySuggestion( - "No event received in delay=" + UNCERTAINTY_DELAY), UNCERTAINTY_DELAY); + // "uncertain" suggestion preempts it within initializationTimeout. If, for some + // reason, the provider does not produce any events then this scheduled suggestion + // will ensure the controller makes at least an "uncertain" suggestion. + suggestDelayed(createEmptySuggestion("No event received from provider in" + + " initializationTimeout=" + initializationTimeout), + initializationTimeout); } } else { // Clear any queued suggestions. @@ -199,7 +199,8 @@ class ControllerImpl extends LocationTimeZoneProviderController { // made, then a new "uncertain" suggestion must be made to indicate the provider no // longer has an opinion and will not be sending updates. if (mLastSuggestion != null && mLastSuggestion.getZoneIds() != null) { - suggestImmediate(createEmptySuggestion("")); + suggestImmediate(createEmptySuggestion( + "Provider disabled, clearing previous suggestion")); } } } @@ -309,21 +310,23 @@ class ControllerImpl extends LocationTimeZoneProviderController { * * <p>Providers are expected to report their uncertainty as soon as they become uncertain, as * this enables the most flexibility for the controller to enable other providers when there are - * multiple ones. The controller is therefore responsible for deciding when to make a + * multiple ones available. The controller is therefore responsible for deciding when to make a * "uncertain" suggestion. * * <p>This method schedules an "uncertain" suggestion (if one isn't already scheduled) to be * made later if nothing else preempts it. It can be preempted if the provider becomes certain * (or does anything else that calls {@link #suggestImmediate(GeolocationTimeZoneSuggestion)}) - * within UNCERTAINTY_DELAY. Preemption causes the scheduled "uncertain" event to be cancelled. - * If the provider repeatedly sends uncertainty events within UNCERTAINTY_DELAY, those events - * are effectively ignored (i.e. the timer is not reset each time). + * within {@link Environment#getUncertaintyDelay()}. Preemption causes the scheduled + * "uncertain" event to be cancelled. If the provider repeatedly sends uncertainty events within + * the uncertainty delay period, those events are effectively ignored (i.e. the timer is not + * reset each time). */ private void scheduleUncertainSuggestionIfNeeded(@Nullable LocationTimeZoneEvent event) { if (mPendingSuggestion == null || mPendingSuggestion.getZoneIds() != null) { GeolocationTimeZoneSuggestion suggestion = createEmptySuggestion( "provider=" + mProvider + " became uncertain, event=" + event); - suggestDelayed(suggestion, UNCERTAINTY_DELAY); + // Only send the empty suggestion after the uncertainty delay. + suggestDelayed(suggestion, mEnvironment.getUncertaintyDelay()); } } @@ -334,6 +337,11 @@ class ControllerImpl extends LocationTimeZoneProviderController { ipw.increaseIndent(); // level 1 ipw.println("mCurrentUserConfiguration=" + mCurrentUserConfiguration); + ipw.println("providerInitializationTimeout=" + + mEnvironment.getProviderInitializationTimeout()); + ipw.println("providerInitializationTimeoutFuzz=" + + mEnvironment.getProviderInitializationTimeoutFuzz()); + ipw.println("uncertaintyDelay=" + mEnvironment.getUncertaintyDelay()); ipw.println("mPendingSuggestion=" + mPendingSuggestion); ipw.println("mLastSuggestion=" + mLastSuggestion); diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java index 3743779b20c9..abfa580b5c98 100644 --- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java @@ -37,6 +37,7 @@ import com.android.server.timezonedetector.ConfigurationInternal; import com.android.server.timezonedetector.Dumpable; import com.android.server.timezonedetector.ReferenceWithHistory; +import java.time.Duration; import java.util.Objects; /** @@ -368,7 +369,8 @@ abstract class LocationTimeZoneProvider implements Dumpable { * #getCurrentState()} is at {@link ProviderState#PROVIDER_STATE_DISABLED}. This method must be * called using the handler thread from the {@link ThreadingDomain}. */ - final void enable(@NonNull ConfigurationInternal currentUserConfiguration) { + final void enable(@NonNull ConfigurationInternal currentUserConfiguration, + @NonNull Duration initializationTimeout) { mThreadingDomain.assertCurrentThread(); synchronized (mSharedLock) { @@ -378,14 +380,14 @@ abstract class LocationTimeZoneProvider implements Dumpable { ProviderState newState = currentState.newState( PROVIDER_STATE_ENABLED, null, currentUserConfiguration, "enable() called"); setCurrentState(newState, false); - onEnable(); + onEnable(initializationTimeout); } } /** * Implemented by subclasses to do work during {@link #enable}. */ - abstract void onEnable(); + abstract void onEnable(@NonNull Duration initializationTimeout); /** * Disables the provider. It is an error* to call this method except when the {@link diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java index 2f75c43594df..88f0f00015c6 100644 --- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java +++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProviderController.java @@ -24,6 +24,7 @@ import com.android.server.timezonedetector.ConfigurationInternal; import com.android.server.timezonedetector.Dumpable; import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion; +import java.time.Duration; import java.util.Objects; /** @@ -100,6 +101,24 @@ abstract class LocationTimeZoneProviderController implements Dumpable { /** Returns the {@link ConfigurationInternal} for the current user of the device. */ abstract ConfigurationInternal getCurrentUserConfigurationInternal(); + + /** + * Returns the value passed to LocationTimeZoneProviders informing them of how long they + * have to return their first time zone suggestion. + */ + abstract Duration getProviderInitializationTimeout(); + + /** + * Returns the extra time granted on top of {@link #getProviderInitializationTimeout()} to + * allow for slop like communication delays. + */ + abstract Duration getProviderInitializationTimeoutFuzz(); + + /** + * Returns the delay allowed after receiving uncertainty from a provider before it should be + * passed on. + */ + abstract Duration getUncertaintyDelay(); } /** diff --git a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java index 79e2b975089d..53afaf06f298 100644 --- a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java +++ b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java @@ -23,6 +23,8 @@ import android.annotation.Nullable; import android.util.IndentingPrintWriter; import android.util.Slog; +import java.time.Duration; + /** * A {@link LocationTimeZoneProvider} that provides minimal responses needed for the {@link * LocationTimeZoneProviderController} to operate correctly when there is no "real" provider @@ -55,7 +57,7 @@ class NullLocationTimeZoneProvider extends LocationTimeZoneProvider { } @Override - void onEnable() { + void onEnable(@NonNull Duration initializationTimeout) { // Report a failure (asynchronously using the mThreadingDomain thread to avoid recursion). mThreadingDomain.post(()-> { // Enter the perm-failed state. diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 2acc60db52e3..0450e5bfd011 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -96,7 +96,9 @@ import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; +import static com.android.internal.util.XmlUtils.readThisIntArrayXml; import static com.android.internal.util.XmlUtils.writeBooleanAttribute; +import static com.android.internal.util.XmlUtils.writeIntArrayXml; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; @@ -229,6 +231,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.StatLogger; +import com.android.internal.util.XmlUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.ServiceThread; @@ -239,6 +242,7 @@ import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener; import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.File; @@ -313,7 +317,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int VERSION_ADDED_NETWORK_ID = 9; private static final int VERSION_SWITCH_UID = 10; private static final int VERSION_ADDED_CYCLE = 11; - private static final int VERSION_LATEST = VERSION_ADDED_CYCLE; + private static final int VERSION_ADDED_NETWORK_TYPES = 12; + private static final int VERSION_LATEST = VERSION_ADDED_NETWORK_TYPES; @VisibleForTesting public static final int TYPE_WARNING = SystemMessage.NOTE_NET_WARNING; @@ -332,6 +337,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String TAG_WHITELIST = "whitelist"; private static final String TAG_RESTRICT_BACKGROUND = "restrict-background"; private static final String TAG_REVOKED_RESTRICT_BACKGROUND = "revoked-restrict-background"; + private static final String TAG_XML_UTILS_INT_ARRAY = "int-array"; private static final String ATTR_VERSION = "version"; private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground"; @@ -360,6 +366,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String ATTR_USAGE_BYTES = "usageBytes"; private static final String ATTR_USAGE_TIME = "usageTime"; private static final String ATTR_OWNER_PACKAGE = "ownerPackage"; + private static final String ATTR_NETWORK_TYPES = "networkTypes"; + private static final String ATTR_XML_UTILS_NAME = "name"; private static final String ACTION_ALLOW_BACKGROUND = "com.android.server.net.action.ALLOW_BACKGROUND"; @@ -2317,13 +2325,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final int subId = readIntAttribute(in, ATTR_SUB_ID); + final String ownerPackage = readStringAttribute(in, ATTR_OWNER_PACKAGE); + + if (version >= VERSION_ADDED_NETWORK_TYPES) { + final int depth = in.getDepth(); + while (XmlUtils.nextElementWithin(in, depth)) { + if (TAG_XML_UTILS_INT_ARRAY.equals(in.getName()) + && ATTR_NETWORK_TYPES.equals( + readStringAttribute(in, ATTR_XML_UTILS_NAME))) { + final int[] networkTypes = + readThisIntArrayXml(in, TAG_XML_UTILS_INT_ARRAY, null); + builder.setNetworkTypes(networkTypes); + } + } + } + final SubscriptionPlan plan = builder.build(); mSubscriptionPlans.put(subId, ArrayUtils.appendElement( SubscriptionPlan.class, mSubscriptionPlans.get(subId), plan)); - - final String ownerPackage = readStringAttribute(in, ATTR_OWNER_PACKAGE); mSubscriptionPlansOwner.put(subId, ownerPackage); - } else if (TAG_UID_POLICY.equals(tag)) { final int uid = readIntAttribute(in, ATTR_UID); final int policy = readIntAttribute(in, ATTR_POLICY); @@ -2519,6 +2539,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writeIntAttribute(out, ATTR_LIMIT_BEHAVIOR, plan.getDataLimitBehavior()); writeLongAttribute(out, ATTR_USAGE_BYTES, plan.getDataUsageBytes()); writeLongAttribute(out, ATTR_USAGE_TIME, plan.getDataUsageTime()); + try { + writeIntArrayXml(plan.getNetworkTypes(), ATTR_NETWORK_TYPES, out); + } catch (XmlPullParserException ignored) { } out.endTag(null, TAG_SUBSCRIPTION_PLAN); } } @@ -3316,7 +3339,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // let in core system components (like the Settings app). final String ownerPackage = mSubscriptionPlansOwner.get(subId); if (Objects.equals(ownerPackage, callingPackage) - || (UserHandle.getCallingAppId() == android.os.Process.SYSTEM_UID)) { + || (UserHandle.getCallingAppId() == android.os.Process.SYSTEM_UID) + || (UserHandle.getCallingAppId() == android.os.Process.PHONE_UID)) { return mSubscriptionPlans.get(subId); } else { Log.w(TAG, "Not returning plans because caller " + callingPackage diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1fd7a73f1174..79882dab48a1 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -8019,7 +8019,7 @@ public class NotificationManagerService extends SystemService { int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch, String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId, boolean sendDelete, int reason, String listenerName, boolean wasPosted) { - ArrayList<NotificationRecord> canceledNotifications = null; + Set<String> childNotifications = null; for (int i = notificationList.size() - 1; i >= 0; --i) { NotificationRecord r = notificationList.get(i); if (includeCurrentProfiles) { @@ -8042,20 +8042,30 @@ public class NotificationManagerService extends SystemService { if (channelId != null && !channelId.equals(r.getChannel().getId())) { continue; } - if (canceledNotifications == null) { - canceledNotifications = new ArrayList<>(); + if (r.getSbn().isGroup() && r.getNotification().isGroupChild()) { + if (childNotifications == null) { + childNotifications = new HashSet<>(); + } + childNotifications.add(r.getKey()); + continue; } notificationList.remove(i); mNotificationsByKey.remove(r.getKey()); r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); - canceledNotifications.add(r); cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); } - if (canceledNotifications != null) { - final int M = canceledNotifications.size(); - for (int i = 0; i < M; i++) { - cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid, - listenerName, false /* sendDelete */, flagChecker, reason); + if (childNotifications != null) { + final int M = notificationList.size(); + for (int i = M - 1; i >= 0; i--) { + NotificationRecord r = notificationList.get(i); + if (childNotifications.contains(r.getKey())) { + // dismiss conditions were checked in the first loop and so don't need to be + // checked again + notificationList.remove(i); + mNotificationsByKey.remove(r.getKey()); + r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL); + cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName); + } } updateLightsLocked(); } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 5bbe49088c02..4c1b700d958e 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -75,6 +75,7 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; @@ -143,6 +144,9 @@ public class LauncherAppsService extends SystemService { private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); + @GuardedBy("mListeners") + private boolean mIsWatchingPackageBroadcasts = false; + private final ShortcutChangeHandler mShortcutChangeHandler; private final Handler mCallbackHandler; @@ -281,7 +285,10 @@ public class LauncherAppsService extends SystemService { * Register a receiver to watch for package broadcasts */ private void startWatchingPackageBroadcasts() { - mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler); + if (!mIsWatchingPackageBroadcasts) { + mPackageMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler); + mIsWatchingPackageBroadcasts = true; + } } /** @@ -291,7 +298,10 @@ public class LauncherAppsService extends SystemService { if (DEBUG) { Log.d(TAG, "Stopped watching for packages"); } - mPackageMonitor.unregister(); + if (mIsWatchingPackageBroadcasts) { + mPackageMonitor.unregister(); + mIsWatchingPackageBroadcasts = false; + } } void checkCallbackCount() { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 4c58b06e79c6..6b291292d42d 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4709,7 +4709,7 @@ public class UserManagerService extends IUserManager.Stub { final boolean running = am.isUserRunning(user.id, 0); final boolean current = user.id == currentUser; if (verbose) { - pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s\n", i, user.id, user.name, + pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s%s\n", i, user.id, user.name, UserInfo.flagsToString(user.flags), running ? " (running)" : "", user.partial ? " (partial)" : "", diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 6fffde14cf7d..e54da9e99852 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -29,6 +29,8 @@ import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES; import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT; import static android.view.InsetsState.ITYPE_CAPTION_BAR; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; +import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT; import static android.view.InsetsState.ITYPE_LEFT_GESTURES; @@ -215,7 +217,8 @@ public class DisplayPolicy { /** Use the transit animation in style resource (see {@link #selectAnimation}). */ static final int ANIMATION_STYLEABLE = 0; - private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR}; + private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, + ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR}; private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR}; private final WindowManagerService mService; @@ -301,6 +304,16 @@ public class DisplayPolicy { private WindowState mNavigationBarAlt = null; @WindowManagerPolicy.AltBarPosition private int mNavigationBarAltPosition = ALT_BAR_UNKNOWN; + // Alternative climate bar for when flexible insets mapping is used to place a climate bar on + // the screen. + private WindowState mClimateBarAlt = null; + @WindowManagerPolicy.AltBarPosition + private int mClimateBarAltPosition = ALT_BAR_UNKNOWN; + // Alternative extra nav bar for when flexible insets mapping is used to place an extra nav bar + // on the screen. + private WindowState mExtraNavBarAlt = null; + @WindowManagerPolicy.AltBarPosition + private int mExtraNavBarAltPosition = ALT_BAR_UNKNOWN; /** See {@link #getNavigationBarFrameHeight} */ private int[] mNavigationBarFrameHeightForRotationDefault = new int[4]; @@ -669,6 +682,12 @@ public class DisplayPolicy { if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) { requestTransientBars(mNavigationBarAlt); } + if (mClimateBarAlt != null && mClimateBarAltPosition == pos) { + requestTransientBars(mClimateBarAlt); + } + if (mExtraNavBarAlt != null && mExtraNavBarAltPosition == pos) { + requestTransientBars(mExtraNavBarAlt); + } } void systemReady() { @@ -936,6 +955,12 @@ public class DisplayPolicy { if (mNavigationBarAlt == win) { mNavigationBarAltPosition = getAltBarPosition(attrs); } + if (mClimateBarAlt == win) { + mClimateBarAltPosition = getAltBarPosition(attrs); + } + if (mExtraNavBarAlt == win) { + mExtraNavBarAltPosition = getAltBarPosition(attrs); + } } /** @@ -1033,6 +1058,16 @@ public class DisplayPolicy { return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; } break; + case ITYPE_CLIMATE_BAR: + if (mClimateBarAlt != null && mClimateBarAlt.isAlive()) { + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; + } + break; + case ITYPE_EXTRA_NAVIGATION_BAR: + if (mExtraNavBarAlt != null && mExtraNavBarAlt.isAlive()) { + return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; + } + break; } } } @@ -1146,6 +1181,14 @@ public class DisplayPolicy { mNavigationBarAlt = win; mNavigationBarAltPosition = getAltBarPosition(attrs); break; + case ITYPE_CLIMATE_BAR: + mClimateBarAlt = win; + mClimateBarAltPosition = getAltBarPosition(attrs); + break; + case ITYPE_EXTRA_NAVIGATION_BAR: + mExtraNavBarAlt = win; + mExtraNavBarAltPosition = getAltBarPosition(attrs); + break; } mDisplayContent.setInsetProvider(insetsType, win, null); } @@ -1194,6 +1237,8 @@ public class DisplayPolicy { switch (insetsType) { case ITYPE_NAVIGATION_BAR: case ITYPE_STATUS_BAR: + case ITYPE_CLIMATE_BAR: + case ITYPE_EXTRA_NAVIGATION_BAR: case ITYPE_CAPTION_BAR: if (++count > 1) { throw new IllegalArgumentException( @@ -1223,6 +1268,12 @@ public class DisplayPolicy { if (mDisplayContent.isDefaultDisplay) { mService.mPolicy.setKeyguardCandidateLw(null); } + } else if (mClimateBarAlt == win) { + mClimateBarAlt = null; + mDisplayContent.setInsetProvider(ITYPE_CLIMATE_BAR, null, null); + } else if (mExtraNavBarAlt == win) { + mExtraNavBarAlt = null; + mDisplayContent.setInsetProvider(ITYPE_EXTRA_NAVIGATION_BAR, null, null); } if (mLastFocusedWindow == win) { mLastFocusedWindow = null; @@ -1311,7 +1362,8 @@ public class DisplayPolicy { return R.anim.dock_left_enter; } } - } else if (win == mStatusBarAlt || win == mNavigationBarAlt) { + } else if (win == mStatusBarAlt || win == mNavigationBarAlt || win == mClimateBarAlt + || win == mExtraNavBarAlt) { if (win.getAttrs().windowAnimations != 0) { return ANIMATION_STYLEABLE; } @@ -2810,10 +2862,19 @@ public class DisplayPolicy { } final InsetsState requestedState = controlTarget.getRequestedInsetsState(); - final @InsetsType int restorePositionTypes = (requestedState.getSourceOrDefaultVisibility( - ITYPE_NAVIGATION_BAR) ? Type.navigationBars() : 0) | ( - requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) ? Type.statusBars() - : 0); + final @InsetsType int restorePositionTypes = + (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR) + ? Type.navigationBars() : 0) + | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) + ? Type.statusBars() : 0) + | (mExtraNavBarAlt != null + && requestedState.getSourceOrDefaultVisibility( + ITYPE_EXTRA_NAVIGATION_BAR) + ? Type.navigationBars() : 0) + | (mClimateBarAlt != null + && requestedState.getSourceOrDefaultVisibility( + ITYPE_CLIMATE_BAR) + ? Type.statusBars() : 0); if (swipeTarget == mNavigationBar && (restorePositionTypes & Type.navigationBars()) != 0) { @@ -3326,6 +3387,16 @@ public class DisplayPolicy { pw.print(prefix); pw.print("mNavigationBarAltPosition="); pw.println(mNavigationBarAltPosition); } + if (mClimateBarAlt != null) { + pw.print(prefix); pw.print("mClimateBarAlt="); pw.println(mClimateBarAlt); + pw.print(prefix); pw.print("mClimateBarAltPosition="); + pw.println(mClimateBarAltPosition); + } + if (mExtraNavBarAlt != null) { + pw.print(prefix); pw.print("mExtraNavBarAlt="); pw.println(mExtraNavBarAlt); + pw.print(prefix); pw.print("mExtraNavBarAltPosition="); + pw.println(mExtraNavBarAltPosition); + } if (mFocusedWindow != null) { pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow); } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index a7f32c09b83b..5bed1862a629 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -16,6 +16,8 @@ package com.android.server.wm; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; +import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; @@ -93,6 +95,8 @@ class InsetsSourceProvider { case ITYPE_STATUS_BAR: case ITYPE_NAVIGATION_BAR: case ITYPE_IME: + case ITYPE_CLIMATE_BAR: + case ITYPE_EXTRA_NAVIGATION_BAR: mControllable = true; break; default: diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index c0bdbff6b761..b59452ffaf36 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.InsetsState.ITYPE_CAPTION_BAR; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_INVALID; @@ -42,6 +43,7 @@ import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowManager; +import android.view.WindowManager.LayoutParams.WindowType; import com.android.internal.protolog.common.ProtoLog; import com.android.server.inputmethod.InputMethodManagerInternal; @@ -115,7 +117,7 @@ class InsetsStateController { } InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) { - final @InternalInsetsType int type = getInsetsTypeForWindowType(attrs.type); + final @InternalInsetsType int type = getInsetsTypeForLayoutParams(attrs); final WindowToken token = mDisplayContent.getWindowToken(attrs.token); final @WindowingMode int windowingMode = token != null ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED; @@ -135,7 +137,9 @@ class InsetsStateController { return false; } - private static @InternalInsetsType int getInsetsTypeForWindowType(int type) { + private static @InternalInsetsType + int getInsetsTypeForLayoutParams(WindowManager.LayoutParams attrs) { + @WindowType int type = attrs.type; switch (type) { case TYPE_STATUS_BAR: return ITYPE_STATUS_BAR; @@ -143,9 +147,22 @@ class InsetsStateController { return ITYPE_NAVIGATION_BAR; case TYPE_INPUT_METHOD: return ITYPE_IME; - default: - return ITYPE_INVALID; } + + // If not one of the types above, check whether an internal inset mapping is specified. + if (attrs.providesInsetsTypes != null) { + for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) { + switch (insetsType) { + case ITYPE_STATUS_BAR: + case ITYPE_NAVIGATION_BAR: + case ITYPE_CLIMATE_BAR: + case ITYPE_EXTRA_NAVIGATION_BAR: + return insetsType; + } + } + } + + return ITYPE_INVALID; } /** @see #getInsetsForDispatch */ @@ -158,14 +175,15 @@ class InsetsStateController { state.removeSource(type); // Navigation bar doesn't get influenced by anything else - if (type == ITYPE_NAVIGATION_BAR) { + if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) { state.removeSource(ITYPE_IME); state.removeSource(ITYPE_STATUS_BAR); + state.removeSource(ITYPE_CLIMATE_BAR); state.removeSource(ITYPE_CAPTION_BAR); } // Status bar doesn't get influenced by caption bar - if (type == ITYPE_STATUS_BAR) { + if (type == ITYPE_STATUS_BAR || type == ITYPE_CLIMATE_BAR) { state.removeSource(ITYPE_CAPTION_BAR); } @@ -336,8 +354,12 @@ class InsetsStateController { @Nullable InsetsControlTarget fakeNavControlling) { onControlChanged(ITYPE_STATUS_BAR, statusControlling); onControlChanged(ITYPE_NAVIGATION_BAR, navControlling); + onControlChanged(ITYPE_CLIMATE_BAR, statusControlling); + onControlChanged(ITYPE_EXTRA_NAVIGATION_BAR, navControlling); onControlFakeTargetChanged(ITYPE_STATUS_BAR, fakeStatusControlling); onControlFakeTargetChanged(ITYPE_NAVIGATION_BAR, fakeNavControlling); + onControlFakeTargetChanged(ITYPE_CLIMATE_BAR, fakeStatusControlling); + onControlFakeTargetChanged(ITYPE_EXTRA_NAVIGATION_BAR, fakeNavControlling); notifyPendingInsetsControlChanged(); } diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 1b649fda1976..44462c33ccdf 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -54,6 +54,7 @@ cc_library_static { "com_android_server_UsbDescriptorParser.cpp", "com_android_server_UsbMidiDevice.cpp", "com_android_server_UsbHostManager.cpp", + "com_android_server_VibratorManagerService.cpp", "com_android_server_VibratorService.cpp", "com_android_server_PersistentDataBlockService.cpp", "com_android_server_am_CachedAppOptimizer.cpp", diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index 8646a53f3390..4c017f5513a2 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -2,6 +2,7 @@ per-file com_android_server_lights_LightsService.cpp = michaelwr@google.com, santoscordon@google.com # Haptics +per-file com_android_server_VibratorManagerService.cpp = michaelwr@google.com per-file com_android_server_VibratorService.cpp = michaelwr@google.com # Input diff --git a/services/core/jni/com_android_server_VibratorManagerService.cpp b/services/core/jni/com_android_server_VibratorManagerService.cpp new file mode 100644 index 000000000000..dae9cefdd1f4 --- /dev/null +++ b/services/core/jni/com_android_server_VibratorManagerService.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "VibratorManagerService" + +#include <nativehelper/JNIHelp.h> +#include "android_runtime/AndroidRuntime.h" +#include "core_jni_helpers.h" +#include "jni.h" + +#include <utils/Log.h> +#include <utils/misc.h> + +#include <vibratorservice/VibratorManagerHalWrapper.h> + +namespace android { + +class NativeVibratorManagerService { +public: + NativeVibratorManagerService() : mHal(std::make_unique<vibrator::LegacyManagerHalWrapper>()) {} + ~NativeVibratorManagerService() = default; + + vibrator::ManagerHalWrapper* hal() const { return mHal.get(); } + +private: + const std::unique_ptr<vibrator::ManagerHalWrapper> mHal; +}; + +static void destroyNativeService(void* ptr) { + NativeVibratorManagerService* service = reinterpret_cast<NativeVibratorManagerService*>(ptr); + if (service) { + delete service; + } +} + +static jlong nativeInit(JNIEnv* /* env */, jclass /* clazz */) { + std::unique_ptr<NativeVibratorManagerService> service = + std::make_unique<NativeVibratorManagerService>(); + return reinterpret_cast<jlong>(service.release()); +} + +static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService)); +} + +static jintArray nativeGetVibratorIds(JNIEnv* env, jclass /* clazz */, jlong servicePtr) { + NativeVibratorManagerService* service = + reinterpret_cast<NativeVibratorManagerService*>(servicePtr); + if (service == nullptr) { + ALOGE("nativeGetVibratorIds failed because native service was not initialized"); + return nullptr; + } + auto result = service->hal()->getVibratorIds(); + if (!result.isOk()) { + return nullptr; + } + std::vector<int32_t> vibratorIds = result.value(); + jintArray ids = env->NewIntArray(vibratorIds.size()); + env->SetIntArrayRegion(ids, 0, vibratorIds.size(), reinterpret_cast<jint*>(vibratorIds.data())); + return ids; +} + +static const JNINativeMethod method_table[] = { + {"nativeInit", "()J", (void*)nativeInit}, + {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer}, + {"nativeGetVibratorIds", "(J)[I", (void*)nativeGetVibratorIds}, +}; + +int register_android_server_VibratorManagerService(JNIEnv* env) { + return jniRegisterNativeMethods(env, "com/android/server/VibratorManagerService", method_table, + NELEM(method_table)); +} + +}; // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index e7f6db959060..48d524433741 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -38,6 +38,7 @@ int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbMidiDevice(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_vr_VrManagerService(JNIEnv* env); +int register_android_server_VibratorManagerService(JNIEnv* env); int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env); int register_android_server_location_GnssLocationProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); @@ -92,6 +93,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_UsbAlsaJackDetector(env); register_android_server_UsbHostManager(env); register_android_server_vr_VrManagerService(env); + register_android_server_VibratorManagerService(env); register_android_server_VibratorService(vm, env); register_android_server_SystemServer(env); register_android_server_location_GnssLocationProvider(env); diff --git a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java index 1fa1b8fc0619..75696dac3b44 100644 --- a/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java +++ b/services/tests/servicestests/src/com/android/internal/location/timezone/LocationTimeZoneProviderRequestTest.java @@ -20,16 +20,20 @@ import static android.location.timezone.ParcelableTestSupport.assertRoundTripPar import org.junit.Test; +import java.time.Duration; + public class LocationTimeZoneProviderRequestTest { @Test public void testParcelable() { LocationTimeZoneProviderRequest.Builder builder = new LocationTimeZoneProviderRequest.Builder() - .setReportLocationTimeZone(true); + .setReportLocationTimeZone(false); assertRoundTripParcelable(builder.build()); - builder.setReportLocationTimeZone(false); + builder.setReportLocationTimeZone(true) + .setInitializationTimeoutMillis(Duration.ofMinutes(5).toMillis()); + assertRoundTripParcelable(builder.build()); } } diff --git a/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java new file mode 100644 index 000000000000..8a22a2f5d92f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/VibratorManagerServiceTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static org.junit.Assert.assertArrayEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.InstrumentationRegistry; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Tests for {@link VibratorManagerService}. + * + * Build/Install/Run: + * atest FrameworksServicesTests:VibratorManagerServiceTest + */ +@Presubmit +public class VibratorManagerServiceTest { + + @Rule public MockitoRule rule = MockitoJUnit.rule(); + + @Mock private VibratorManagerService.NativeWrapper mNativeWrapperMock; + + @Before + public void setUp() throws Exception { + } + + private VibratorManagerService createService() { + return new VibratorManagerService(InstrumentationRegistry.getContext(), + new VibratorManagerService.Injector() { + @Override + VibratorManagerService.NativeWrapper getNativeWrapper() { + return mNativeWrapperMock; + } + }); + } + + @Test + public void createService_initializesNativeService() { + createService(); + verify(mNativeWrapperMock).init(); + } + + @Test + public void getVibratorIds_withNullResultFromNative_returnsEmptyArray() { + when(mNativeWrapperMock.getVibratorIds()).thenReturn(null); + assertArrayEquals(new int[0], createService().getVibratorIds()); + } + + @Test + public void getVibratorIds_withNonEmptyResultFromNative_returnsSameArray() { + when(mNativeWrapperMock.getVibratorIds()).thenReturn(new int[]{ 1, 2 }); + assertArrayEquals(new int[]{ 1, 2 }, createService().getVibratorIds()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java index dbaad6633e98..631b8d3cb1ea 100644 --- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java +++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java @@ -18,7 +18,6 @@ package com.android.server.location.timezone; import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_SUCCESS; import static android.location.timezone.LocationTimeZoneEvent.EVENT_TYPE_UNCERTAIN; -import static com.android.server.location.timezone.ControllerImpl.UNCERTAINTY_DELAY; import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DISABLED; import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_ENABLED; import static com.android.server.location.timezone.TestSupport.USER1_CONFIG_GEO_DETECTION_DISABLED; @@ -47,6 +46,7 @@ import com.android.server.timezonedetector.TestState; import org.junit.Before; import org.junit.Test; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -92,7 +92,8 @@ public class ControllerImplTest { mTestLocationTimeZoneProvider.assertInitialized(); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertNextQueueItemIsDelayed(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); } @@ -121,7 +122,8 @@ public class ControllerImplTest { mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); mTestCallback.assertNoSuggestionMade(); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); // Simulate time passing with no event being received. mTestThreadingDomain.executeNext(); @@ -140,7 +142,8 @@ public class ControllerImplTest { controllerImpl.initialize(testEnvironment, mTestCallback); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Simulate a location event being received by the provider. This should cause a suggestion @@ -163,7 +166,8 @@ public class ControllerImplTest { controllerImpl.initialize(testEnvironment, mTestCallback); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Simulate a location event being received by the provider. This should cause a suggestion @@ -203,7 +207,8 @@ public class ControllerImplTest { controllerImpl.initialize(testEnvironment, mTestCallback); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Simulate a location event being received by the provider. This should cause a suggestion @@ -216,15 +221,16 @@ public class ControllerImplTest { mTestCallback.assertSuggestionMadeAndCommit( USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getTimeZoneIds()); - // Uncertainty should cause + // Uncertainty should cause a suggestion to (only) be queued. mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent( USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + mTestThreadingDomain.assertSingleDelayedQueueItem(testEnvironment.getUncertaintyDelay()); mTestCallback.assertNoSuggestionMade(); - // And a third event should cause yet another suggestion. + // And a third event should cause yet another suggestion and for the queued item to be + // removed. mTestLocationTimeZoneProvider.simulateLocationTimeZoneEvent( USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT2); @@ -250,7 +256,8 @@ public class ControllerImplTest { testEnvironment.simulateConfigChange(USER1_CONFIG_GEO_DETECTION_ENABLED); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertNextQueueItemIsDelayed(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Now signal a config change so that geo detection is disabled. @@ -270,7 +277,8 @@ public class ControllerImplTest { controllerImpl.initialize(testEnvironment, mTestCallback); mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Simulate a location event being received by the provider. This should cause a suggestion @@ -304,7 +312,8 @@ public class ControllerImplTest { // There should be a runnable scheduled to suggest uncertainty if no event is received. mTestLocationTimeZoneProvider.assertIsEnabled(USER1_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + Duration expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Have the provider suggest a time zone. @@ -328,7 +337,8 @@ public class ControllerImplTest { int[] expectedStateTransitions = { PROVIDER_STATE_DISABLED, PROVIDER_STATE_ENABLED }; mTestLocationTimeZoneProvider.assertStateChangesAndCommit(expectedStateTransitions); mTestLocationTimeZoneProvider.assertConfig(USER2_CONFIG_GEO_DETECTION_ENABLED); - mTestThreadingDomain.assertSingleDelayedQueueItem(UNCERTAINTY_DELAY); + expectedTimeout = expectedProviderInitializationTimeout(); + mTestThreadingDomain.assertSingleDelayedQueueItem(expectedTimeout); mTestCallback.assertNoSuggestionMade(); // Simulate no event being received, and time passing. @@ -351,8 +361,18 @@ public class ControllerImplTest { return builder.build(); } + + private Duration expectedProviderInitializationTimeout() { + return TestEnvironment.PROVIDER_INITIALIZATION_TIMEOUT + .plus(TestEnvironment.PROVIDER_INITIALIZATION_TIMEOUT_FUZZ); + } + private static class TestEnvironment extends LocationTimeZoneProviderController.Environment { + static final Duration PROVIDER_INITIALIZATION_TIMEOUT = Duration.ofMinutes(5); + static final Duration PROVIDER_INITIALIZATION_TIMEOUT_FUZZ = Duration.ofMinutes(1); + private static final Duration UNCERTAINTY_DELAY = Duration.ofMinutes(3); + private final LocationTimeZoneProviderController mController; private ConfigurationInternal mConfigurationInternal; @@ -369,6 +389,21 @@ public class ControllerImplTest { return mConfigurationInternal; } + @Override + Duration getProviderInitializationTimeout() { + return PROVIDER_INITIALIZATION_TIMEOUT; + } + + @Override + Duration getProviderInitializationTimeoutFuzz() { + return PROVIDER_INITIALIZATION_TIMEOUT_FUZZ; + } + + @Override + Duration getUncertaintyDelay() { + return UNCERTAINTY_DELAY; + } + void simulateConfigChange(ConfigurationInternal newConfig) { ConfigurationInternal oldConfig = mConfigurationInternal; mConfigurationInternal = Objects.requireNonNull(newConfig); @@ -432,7 +467,7 @@ public class ControllerImplTest { } @Override - void onEnable() { + void onEnable(Duration initializationTimeout) { // Nothing needed for tests. } @@ -464,7 +499,7 @@ public class ControllerImplTest { /** * Asserts the provider's config matches the expected, and the current state is set - * accordinly. Commits the latest changes to the state. + * accordingly. Commits the latest changes to the state. */ void assertIsEnabled(@NonNull ConfigurationInternal expectedConfig) { assertConfig(expectedConfig); diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java index 7c882fc1f154..5542db0b5ae3 100644 --- a/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/location/timezone/NullLocationTimeZoneProviderTest.java @@ -34,6 +34,8 @@ import com.android.server.timezonedetector.TestState; import org.junit.Before; import org.junit.Test; +import java.time.Duration; + /** * Tests for {@link NullLocationTimeZoneProvider} and, indirectly, the class it extends * {@link LocationTimeZoneProvider}. @@ -73,7 +75,8 @@ public class NullLocationTimeZoneProviderTest { provider.initialize(providerState -> mTestController.onProviderStateChange(providerState)); ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED; - provider.enable(config); + Duration arbitraryInitializationTimeout = Duration.ofMinutes(5); + provider.enable(config, arbitraryInitializationTimeout); // The StubbedProvider should enters enabled state, but immediately schedule a runnable to // switch to perm failure. diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java b/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java index 70ff22d17513..def919e79731 100644 --- a/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java +++ b/services/tests/servicestests/src/com/android/server/location/timezone/TestThreadingDomain.java @@ -105,8 +105,8 @@ class TestThreadingDomain extends ThreadingDomain { assertTrue(getNextQueueItemDelayMillis() == 0); } - void assertNextQueueItemIsDelayed(Duration expectedDelay) { - assertTrue(getNextQueueItemDelayMillis() == expectedDelay.toMillis()); + private void assertNextQueueItemIsDelayed(Duration expectedDelay) { + assertEquals(getNextQueueItemDelayMillis(), expectedDelay.toMillis()); } void assertQueueEmpty() { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 1a4b119a6c99..ed6a20b97d37 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -74,6 +74,7 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -185,6 +186,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; @@ -563,6 +565,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .getUiAutomation().dropShellPermissionIdentity(); } + private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, + int uid) { + // mimics receive broadcast that package is (un)suspended + // but does not actually (un)suspend the package + final Bundle extras = new Bundle(); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, + new String[]{pkg}); + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); + + final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED + : Intent.ACTION_PACKAGES_UNSUSPENDED; + final Intent intent = new Intent(action); + intent.putExtras(extras); + + mPackageIntentReceiver.onReceive(getContext(), intent); + } + + private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { + // mimics receive broadcast that package is (un)distracting + // but does not actually register that info with packagemanager + final Bundle extras = new Bundle(); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); + extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); + + final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); + intent.putExtras(extras); + + mPackageIntentReceiver.onReceive(getContext(), intent); + } + private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() { ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>(); changed.put(true, new ArrayList<>()); @@ -7066,34 +7099,39 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertTrue(mService.isVisibleToListener(sbn, info)); } - private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, - int uid) { - // mimics receive broadcast that package is (un)suspended - // but does not actually (un)suspend the package - final Bundle extras = new Bundle(); - extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, - new String[]{pkg}); - extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); + @Test + public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() { + final NotificationRecord parent = spy(generateNotificationRecord( + mTestNotificationChannel, 1, "group", true)); + final NotificationRecord child = spy(generateNotificationRecord( + mTestNotificationChannel, 2, "group", false)); + mService.addNotification(parent); + mService.addNotification(child); - final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED - : Intent.ACTION_PACKAGES_UNSUSPENDED; - final Intent intent = new Intent(action); - intent.putExtras(extras); + InOrder inOrder = inOrder(parent, child); - mPackageIntentReceiver.onReceive(getContext(), intent); + mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), + parent.getUserId()); + waitForIdle(); + inOrder.verify(parent).recordDismissalSentiment(anyInt()); + inOrder.verify(child).recordDismissalSentiment(anyInt()); } - private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { - // mimics receive broadcast that package is (un)distracting - // but does not actually register that info with packagemanager - final Bundle extras = new Bundle(); - extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); - extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); - extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); + @Test + public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() { + final NotificationRecord parent = spy(generateNotificationRecord( + mTestNotificationChannel, 1, "group", true)); + final NotificationRecord child = spy(generateNotificationRecord( + mTestNotificationChannel, 2, "group", false)); + mService.addNotification(child); + mService.addNotification(parent); - final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); - intent.putExtras(extras); + InOrder inOrder = inOrder(parent, child); - mPackageIntentReceiver.onReceive(getContext(), intent); + mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), + parent.getUserId()); + waitForIdle(); + inOrder.verify(parent).recordDismissalSentiment(anyInt()); + inOrder.verify(child).recordDismissalSentiment(anyInt()); } } 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 951118125f6e..2920c1da3f24 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -20,6 +20,8 @@ import static android.view.Gravity.BOTTOM; import static android.view.Gravity.LEFT; import static android.view.Gravity.RIGHT; import static android.view.Gravity.TOP; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; +import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.ITYPE_TOP_GESTURES; @@ -218,10 +220,15 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { @Test public void addingWindow_throwsException_WithMultipleInsetTypes() { - WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel"); - win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}; + WindowState win1 = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel"); + win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}; + + expectThrows(IllegalArgumentException.class, () -> addWindow(win1)); + + WindowState win2 = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel"); + win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR}; - expectThrows(IllegalArgumentException.class, () -> addWindow(win)); + expectThrows(IllegalArgumentException.class, () -> addWindow(win2)); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 4a4974355ea2..e2cd8a909266 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -20,6 +20,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; +import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; @@ -284,12 +286,17 @@ public class InsetsStateControllerTest extends WindowTestsBase { public void testBarControllingWinChanged() { final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar"); final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState climateBar = createWindow(null, TYPE_APPLICATION, "climateBar"); + final WindowState extraNavBar = createWindow(null, TYPE_APPLICATION, "extraNavBar"); final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null); getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null); + getController().getSourceProvider(ITYPE_CLIMATE_BAR).setWindow(climateBar, null, null); + getController().getSourceProvider(ITYPE_EXTRA_NAVIGATION_BAR).setWindow(extraNavBar, null, + null); getController().onBarControlTargetChanged(app, null, app, null); InsetsSourceControl[] controls = getController().getControlsForDispatch(app); - assertEquals(2, controls.length); + assertEquals(4, controls.length); } @Test diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt index 0a7e1581815e..72a739c5c879 100644 --- a/telephony/api/system-current.txt +++ b/telephony/api/system-current.txt @@ -933,11 +933,11 @@ package android.telephony.data { method public int getSuggestedRetryTime(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; - field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 2; // 0x2 - field public static final int HANDOVER_FAILURE_MODE_LEGACY = 1; // 0x1 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 3; // 0x3 - field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 4; // 0x4 - field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 + field public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; // 0x0 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; // 0x2 + field public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; // 0x3 + field public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; // 0xffffffff field public static final int LINK_STATUS_ACTIVE = 2; // 0x2 field public static final int LINK_STATUS_DORMANT = 1; // 0x1 field public static final int LINK_STATUS_INACTIVE = 0; // 0x0 diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0ec27933dc36..a82d98807ad3 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1888,8 +1888,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -1941,8 +1941,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -2010,8 +2010,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -2088,8 +2088,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -2126,8 +2126,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -2210,8 +2210,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -2247,8 +2247,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -3723,8 +3723,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -3761,8 +3761,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -4015,8 +4015,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. @@ -4054,8 +4054,8 @@ public class TelephonyManager { * * <p>Starting with API level 29, persistent device identifiers are guarded behind additional * restrictions, and apps are recommended to use resettable identifiers (see <a - * href="c"> Best practices for unique identifiers</a>). This method can be invoked if one of - * the following requirements is met: + * href="/training/articles/user-data-ids">Best practices for unique identifiers</a>). This + * method can be invoked if one of the following requirements is met: * <ul> * <li>If the calling app has been granted the READ_PRIVILEGED_PHONE_STATE permission; this * is a privileged permission that can only be granted to apps preloaded on the device. diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index 5ead8decdb63..39859b1e4fdb 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -80,33 +80,33 @@ public final class DataCallResponse implements Parcelable { /** * Data handover failure mode is unknown. */ - public static final int HANDOVER_FAILURE_MODE_UNKNOWN = 0; + public static final int HANDOVER_FAILURE_MODE_UNKNOWN = -1; /** * Perform fallback to the source data transport on data handover failure using * the legacy logic, which is fallback if the fail cause is * {@link DataFailCause#HANDOFF_PREFERENCE_CHANGED}. */ - public static final int HANDOVER_FAILURE_MODE_LEGACY = 1; + public static final int HANDOVER_FAILURE_MODE_LEGACY = 0; /** * Perform fallback to the source data transport on data handover failure. */ - public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 2; + public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; /** * Do not perform fallback to the source data transport on data handover failure. - * Frameworks should keep retrying handover by sending + * Framework will retry setting up a new data connection by sending * {@link DataService#REQUEST_REASON_HANDOVER} request to the underlying {@link DataService}. */ - public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 3; + public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER = 2; /** * Do not perform fallback to the source transport on data handover failure. - * Frameworks should retry setup a new data connection by sending + * Framework will retry setting up a new data connection by sending * {@link DataService#REQUEST_REASON_NORMAL} request to the underlying {@link DataService}. */ - public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 4; + public static final int HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL = 3; private final @DataFailureCause int mCause; private final int mSuggestedRetryTime; @@ -332,6 +332,7 @@ public final class DataCallResponse implements Parcelable { .append(" mtu=").append(getMtu()) .append(" mtuV4=").append(getMtuV4()) .append(" mtuV6=").append(getMtuV6()) + .append(" handoverFailureMode=").append(getHandoverFailureMode()) .append("}"); return sb.toString(); } @@ -361,14 +362,15 @@ public final class DataCallResponse implements Parcelable { && mPcscfAddresses.containsAll(other.mPcscfAddresses) && mMtu == other.mMtu && mMtuV4 == other.mMtuV4 - && mMtuV6 == other.mMtuV6; + && mMtuV6 == other.mMtuV6 + && mHandoverFailureMode == other.mHandoverFailureMode; } @Override public int hashCode() { return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses, - mMtu, mMtuV4, mMtuV6); + mMtu, mMtuV4, mMtuV6, mHandoverFailureMode); } @Override |