diff options
111 files changed, 1073 insertions, 296 deletions
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml index 57595a213d20..de2a3f2c4bfc 100644 --- a/apct-tests/perftests/autofill/AndroidManifest.xml +++ b/apct-tests/perftests/autofill/AndroidManifest.xml @@ -16,6 +16,16 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.perftests.autofill"> + <uses-permission android:name="android.permission.CONTROL_KEYGUARD" /> + <uses-permission android:name="android.permission.DEVICE_POWER" /> + <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" /> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.MANAGE_USERS" /> + <uses-permission android:name="android.permission.REAL_GET_TASKS" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> + <application> <uses-library android:name="android.test.runner" /> <activity android:name="android.perftests.utils.PerfTestActivity" diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS index def9f401e51f..062ffd41348a 100644 --- a/cmds/idmap2/OWNERS +++ b/cmds/idmap2/OWNERS @@ -1,3 +1,4 @@ set noparent +toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 6cfa39cd2337..ab645960ee2c 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -1452,18 +1452,27 @@ public class WallpaperManager { mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; - boolean ok = false; + final Bitmap tmp = BitmapFactory.decodeStream(resources.openRawResource(resid)); try { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - copyStreamToWallpaperFile(resources.openRawResource(resid), fos); - // The 'close()' is the trigger for any server-side image manipulation, - // so we must do that before waiting for completion. - fos.close(); - completion.waitForCompletion(); + // If the stream can't be decoded, treat it as an invalid input. + if (tmp != null) { + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); + // The 'close()' is the trigger for any server-side image manipulation, + // so we must do that before waiting for completion. + fos.close(); + completion.waitForCompletion(); + } else { + throw new IllegalArgumentException( + "Resource 0x" + Integer.toHexString(resid) + " is invalid"); + } } finally { // Might be redundant but completion shouldn't wait unless the write // succeeded; this is a fallback if it threw past the close+wait. IoUtils.closeQuietly(fos); + if (tmp != null) { + tmp.recycle(); + } } } } catch (RemoteException e) { @@ -1705,13 +1714,22 @@ public class WallpaperManager { result, which, completion, mContext.getUserId()); if (fd != null) { FileOutputStream fos = null; + final Bitmap tmp = BitmapFactory.decodeStream(bitmapData); try { - fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); - copyStreamToWallpaperFile(bitmapData, fos); - fos.close(); - completion.waitForCompletion(); + // If the stream can't be decoded, treat it as an invalid input. + if (tmp != null) { + fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); + tmp.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.close(); + completion.waitForCompletion(); + } else { + throw new IllegalArgumentException("InputStream is invalid"); + } } finally { IoUtils.closeQuietly(fos); + if (tmp != null) { + tmp.recycle(); + } } } } catch (RemoteException e) { diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index a0d2977cf09a..01875eda2eca 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -16,6 +16,7 @@ package android.app.admin; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; @@ -77,6 +78,13 @@ public abstract class DevicePolicyManagerInternal { OnCrossProfileWidgetProvidersChangeListener listener); /** + * @param userHandle the handle of the user whose profile owner is being fetched. + * @return the configured supervision app if it exists and is the device owner or policy owner. + */ + public abstract @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent( + @NonNull UserHandle userHandle); + + /** * Checks if an app with given uid is an active device owner of its user. * * <p>This takes the DPMS lock. DO NOT call from PM/UM/AM with their lock held. diff --git a/core/java/android/content/integrity/OWNERS b/core/java/android/content/integrity/OWNERS index a1fe59c862d2..20c758aedd67 100644 --- a/core/java/android/content/integrity/OWNERS +++ b/core/java/android/content/integrity/OWNERS @@ -1,3 +1,5 @@ # Bug component: 722021 +toddke@android.com +toddke@google.com patb@google.com diff --git a/core/java/android/content/om/OWNERS b/core/java/android/content/om/OWNERS index 9c473360a46a..3669817e9844 100644 --- a/core/java/android/content/om/OWNERS +++ b/core/java/android/content/om/OWNERS @@ -1,4 +1,6 @@ # Bug component: 568631 +toddke@android.com +toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/content/pm/OWNERS b/core/java/android/content/pm/OWNERS index 128bfb99ccd4..4e674f6ec9a8 100644 --- a/core/java/android/content/pm/OWNERS +++ b/core/java/android/content/pm/OWNERS @@ -1,9 +1,11 @@ # Bug component: 36137 +toddke@android.com +toddke@google.com patb@google.com per-file PackageParser.java = set noparent -per-file PackageParser.java = chiuwinson@google.com,patb@google.com +per-file PackageParser.java = chiuwinson@google.com,patb@google.com,toddke@google.com per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file AppSearchPerson.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/java/android/content/pm/dex/OWNERS b/core/java/android/content/pm/dex/OWNERS index b590f659a5d4..267e5d58f9a6 100644 --- a/core/java/android/content/pm/dex/OWNERS +++ b/core/java/android/content/pm/dex/OWNERS @@ -1,5 +1,7 @@ # Bug component: 86431 +toddke@android.com +toddke@google.com patb@google.com calin@google.com ngeoffray@google.com diff --git a/core/java/android/content/pm/parsing/OWNERS b/core/java/android/content/pm/parsing/OWNERS index 445a8330037b..8049d5cb7fa2 100644 --- a/core/java/android/content/pm/parsing/OWNERS +++ b/core/java/android/content/pm/parsing/OWNERS @@ -2,3 +2,4 @@ chiuwinson@google.com patb@google.com +toddke@google.com diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS index f9c51dd2ae58..cf7e6890876a 100644 --- a/core/java/android/content/pm/permission/OWNERS +++ b/core/java/android/content/pm/permission/OWNERS @@ -2,5 +2,7 @@ include platform/frameworks/base:/core/java/android/permission/OWNERS +toddke@android.com +toddke@google.com patb@google.com diff --git a/core/java/android/content/pm/split/OWNERS b/core/java/android/content/pm/split/OWNERS index b8fa1a93ed78..3d126d297e60 100644 --- a/core/java/android/content/pm/split/OWNERS +++ b/core/java/android/content/pm/split/OWNERS @@ -1,3 +1,5 @@ # Bug component: 36137 +toddke@android.com +toddke@google.com patb@google.com diff --git a/core/java/android/content/pm/verify/domain/OWNERS b/core/java/android/content/pm/verify/domain/OWNERS index 445a8330037b..c669112e0512 100644 --- a/core/java/android/content/pm/verify/domain/OWNERS +++ b/core/java/android/content/pm/verify/domain/OWNERS @@ -2,3 +2,4 @@ chiuwinson@google.com patb@google.com +toddke@google.com
\ No newline at end of file diff --git a/core/java/android/content/res/OWNERS b/core/java/android/content/res/OWNERS index 7460a14182e5..d12d920b2a54 100644 --- a/core/java/android/content/res/OWNERS +++ b/core/java/android/content/res/OWNERS @@ -1,4 +1,6 @@ # Bug component: 568761 +toddke@android.com +toddke@google.com patb@google.com zyy@google.com diff --git a/core/java/android/hardware/OWNERS b/core/java/android/hardware/OWNERS index 4143bfcb9c0a..95f13b5c1d8c 100644 --- a/core/java/android/hardware/OWNERS +++ b/core/java/android/hardware/OWNERS @@ -1,5 +1,5 @@ # Camera -per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,zhijunhe@google.com,jchowdhary@google.com +per-file *Camera*=cychen@google.com,epeev@google.com,etalvala@google.com,shuzhenwang@google.com,yinchiayeh@google.com,zhijunhe@google.com,jchowdhary@google.com # Sensor Privacy per-file *SensorPrivacy* = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS diff --git a/core/java/android/os/incremental/OWNERS b/core/java/android/os/incremental/OWNERS index 363486905c93..47eee6406206 100644 --- a/core/java/android/os/incremental/OWNERS +++ b/core/java/android/os/incremental/OWNERS @@ -1,5 +1,6 @@ # Bug component: 554432 alexbuy@google.com schfan@google.com +toddke@google.com zyy@google.com patb@google.com diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2a82d992471d..675297d024ee 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -800,11 +800,7 @@ public final class ViewRootImpl implements ViewParent, context); mCompatibleVisibilityInfo = new SystemUiVisibilityInfo(); mAccessibilityManager = AccessibilityManager.getInstance(context); - mAccessibilityManager.addAccessibilityStateChangeListener( - mAccessibilityInteractionConnectionManager, mHandler); mHighContrastTextManager = new HighContrastTextManager(); - mAccessibilityManager.addHighTextContrastStateChangeListener( - mHighContrastTextManager, mHandler); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; @@ -1004,8 +1000,6 @@ public final class ViewRootImpl implements ViewParent, mView = view; mAttachInfo.mDisplayState = mDisplay.getState(); - mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); - mViewLayoutDirectionInitial = mView.getRawLayoutDirection(); mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); @@ -1198,6 +1192,7 @@ public final class ViewRootImpl implements ViewParent, "Unable to add window -- unknown error code " + res); } + registerListeners(); if ((res & WindowManagerGlobal.ADD_FLAG_USE_BLAST) != 0) { mUseBLASTAdapter = true; } @@ -1254,6 +1249,28 @@ public final class ViewRootImpl implements ViewParent, } } + /** + * Register any kind of listeners if setView was success. + */ + private void registerListeners() { + mAccessibilityManager.addAccessibilityStateChangeListener( + mAccessibilityInteractionConnectionManager, mHandler); + mAccessibilityManager.addHighTextContrastStateChangeListener( + mHighContrastTextManager, mHandler); + mDisplayManager.registerDisplayListener(mDisplayListener, mHandler); + } + + /** + * Unregister all listeners while detachedFromWindow. + */ + private void unregisterListeners() { + mAccessibilityManager.removeAccessibilityStateChangeListener( + mAccessibilityInteractionConnectionManager); + mAccessibilityManager.removeHighTextContrastStateChangeListener( + mHighContrastTextManager); + mDisplayManager.unregisterDisplayListener(mDisplayListener); + } + private void setTag() { final String[] split = mWindowAttributes.getTitle().toString().split("\\."); if (split.length > 0) { @@ -4979,10 +4996,6 @@ public final class ViewRootImpl implements ViewParent, } mAccessibilityInteractionConnectionManager.ensureNoConnection(); - mAccessibilityManager.removeAccessibilityStateChangeListener( - mAccessibilityInteractionConnectionManager); - mAccessibilityManager.removeHighTextContrastStateChangeListener( - mHighContrastTextManager); removeSendWindowContentChangedCallback(); destroyHardwareRenderer(); @@ -5015,8 +5028,7 @@ public final class ViewRootImpl implements ViewParent, mInputEventReceiver = null; } - mDisplayManager.unregisterDisplayListener(mDisplayListener); - + unregisterListeners(); unscheduleTraversals(); } diff --git a/core/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java index 3e0075857402..0c4d273f6ce8 100644 --- a/core/java/android/window/SplashScreen.java +++ b/core/java/android/window/SplashScreen.java @@ -92,6 +92,9 @@ public interface SplashScreen { * overrides and persists the theme used for the {@link SplashScreen} of this application. * <p> * To reset to the default theme, set this the themeId to {@link Resources#ID_NULL}. + * <p> + * <b>Note:</b> The theme name must be stable across versions, otherwise it won't be found + * after your application is updated. */ void setSplashScreenTheme(@StyleRes int themeId); diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index acf20d701eeb..6a875d1be65d 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -316,7 +316,8 @@ public final class SplashScreenView extends FrameLayout { } private SurfaceView createSurfaceView(@NonNull SplashScreenView view) { - final SurfaceView surfaceView = new SurfaceView(view.getContext()); + final Context viewContext = view.getContext(); + final SurfaceView surfaceView = new SurfaceView(viewContext); surfaceView.setPadding(0, 0, 0, 0); surfaceView.setBackground(mIconBackground); if (mSurfacePackage == null) { @@ -326,10 +327,10 @@ public final class SplashScreenView extends FrameLayout { + Thread.currentThread().getId()); } - SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext, - mContext.getDisplay(), + SurfaceControlViewHost viewHost = new SurfaceControlViewHost(viewContext, + viewContext.getDisplay(), surfaceView.getHostToken()); - ImageView imageView = new ImageView(mContext); + ImageView imageView = new ImageView(viewContext); imageView.setBackground(mIconDrawable); viewHost.setView(imageView, mIconSize, mIconSize); SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage(); diff --git a/core/java/com/android/internal/infra/OWNERS b/core/java/com/android/internal/infra/OWNERS index e69de29bb2d1..45503582b2c5 100644 --- a/core/java/com/android/internal/infra/OWNERS +++ b/core/java/com/android/internal/infra/OWNERS @@ -0,0 +1,6 @@ +per-file AndroidFuture.java = eugenesusla@google.com +per-file RemoteStream.java = eugenesusla@google.com +per-file PerUser.java = eugenesusla@google.com +per-file ServiceConnector.java = eugenesusla@google.com +per-file AndroidFuture.aidl = eugenesusla@google.com +per-file IAndroidFuture.aidl = eugenesusla@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS index 2b7f8b2749fd..100a605dc175 100644 --- a/core/java/com/android/internal/util/OWNERS +++ b/core/java/com/android/internal/util/OWNERS @@ -4,3 +4,4 @@ per-file *Notification* = file:/services/core/java/com/android/server/notificati per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS per-file Protocol* = etancohen@google.com, lorenzo@google.com per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com +per-file DataClass* = eugenesusla@google.com
\ No newline at end of file diff --git a/core/java/com/android/internal/util/function/pooled/OWNERS b/core/java/com/android/internal/util/function/pooled/OWNERS index e69de29bb2d1..da723b3b67da 100644 --- a/core/java/com/android/internal/util/function/pooled/OWNERS +++ b/core/java/com/android/internal/util/function/pooled/OWNERS @@ -0,0 +1 @@ +eugenesusla@google.com
\ No newline at end of file diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS index 81bad6a4ba69..554e27890476 100644 --- a/core/java/com/android/server/OWNERS +++ b/core/java/com/android/server/OWNERS @@ -1 +1 @@ -per-file SystemConfig.java = patb@google.com +per-file SystemConfig.java = toddke@google.com,patb@google.com diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 790c39e73bff..b4aa00763ed3 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -1,9 +1,9 @@ # Camera per-file *Camera*,*camera* = cychen@google.com, epeev@google.com, etalvala@google.com -per-file *Camera*,*camera* = shuzhenwang@google.com, zhijunhe@google.com +per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhijunhe@google.com # Connectivity -per-file android_net_* = jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com +per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com # CPU per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS diff --git a/core/proto/OWNERS b/core/proto/OWNERS index 931ef4478098..78650ed34813 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -5,6 +5,7 @@ joeo@google.com singhtejinder@google.com yanmin@google.com yaochen@google.com +yro@google.com zhouwenjie@google.com # Frameworks @@ -12,7 +13,7 @@ ogunwale@google.com jjaggi@google.com kwekua@google.com roosa@google.com -per-file package_item_info.proto = patb@google.com +per-file package_item_info.proto = toddke@google.com,patb@google.com per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/android/app/usage/OWNERS per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS diff --git a/core/res/OWNERS b/core/res/OWNERS index e241dd6e3615..165dcad896c9 100644 --- a/core/res/OWNERS +++ b/core/res/OWNERS @@ -22,6 +22,7 @@ patb@google.com shanh@google.com svetoslavganov@android.com svetoslavganov@google.com +toddke@google.com tsuji@google.com yamasani@google.com diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index fb7cddaf281a..2f334989b53a 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1908,8 +1908,9 @@ STREAM_MUSIC as if it's on TV platform. --> <bool name="config_single_volume">false</bool> - <!-- Flag indicating whether the volume panel should show remote sessions. --> - <bool name="config_volumeShowRemoteSessions">true</bool> + <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions + on grouped devices. --> + <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool> <!-- Flag indicating that an outbound call must have a call capable phone account that has declared it can process the call's handle. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8ed799111776..4db6499569b3 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4432,7 +4432,7 @@ <java-symbol type="dimen" name="config_wallpaperDimAmount" /> - <java-symbol type="bool" name="config_volumeShowRemoteSessions" /> + <java-symbol type="bool" name="config_volumeAdjustmentForRemoteGroupSessions" /> <!-- List of shared library packages that should be loaded by the classloader after the code and resources provided by applications. --> diff --git a/data/etc/OWNERS b/data/etc/OWNERS index 2c93d5abc155..ea23aba16d12 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -8,6 +8,8 @@ jsharkey@google.com lorenzo@google.com svetoslavganov@android.com svetoslavganov@google.com +toddke@android.com +toddke@google.com patb@google.com yamasani@google.com diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java index b7235a31af03..a568c28dacf1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java @@ -83,6 +83,19 @@ public class DisplayLayout { private boolean mHasStatusBar = false; private int mNavBarFrameHeight = 0; + /** + * Different from {@link #equals(Object)}, this method compares the basic geometry properties + * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout. + * @return {@code true} if the given {@link DisplayLayout} is identical geometry wise. + */ + public boolean isSameGeometry(@NonNull DisplayLayout other) { + return mWidth == other.mWidth + && mHeight == other.mHeight + && mRotation == other.mRotation + && mDensityDpi == other.mDensityDpi + && Objects.equals(mCutout, other.mCutout); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 63f1985aa86e..8967457802a7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -76,7 +76,6 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipUtils; import java.io.PrintWriter; -import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; @@ -441,7 +440,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } private void onDisplayChanged(DisplayLayout layout, boolean saveRestoreSnapFraction) { - if (Objects.equals(layout, mPipBoundsState.getDisplayLayout())) { + if (mPipBoundsState.getDisplayLayout().isSameGeometry(layout)) { return; } Runnable updateDisplayLayout = () -> { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java index 29326ec90e31..cdd745ff9794 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java @@ -50,6 +50,7 @@ import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; +import android.view.ContextThemeWrapper; import android.view.SurfaceControl; import android.view.View; import android.window.SplashScreenView; @@ -299,6 +300,11 @@ public class SplashscreenContentDrawer { } } + /** Creates the wrapper with system theme to avoid unexpected styles from app. */ + ContextThemeWrapper createViewContextWrapper(Context appContext) { + return new ContextThemeWrapper(appContext, mContext.getTheme()); + } + /** The configuration of the splash screen window. */ public static class SplashScreenWindowAttrs { private int mWindowBgResId = 0; @@ -472,7 +478,8 @@ public class SplashscreenContentDrawer { } Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon"); - final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext) + final ContextThemeWrapper wrapper = createViewContextWrapper(mContext); + final SplashScreenView.Builder builder = new SplashScreenView.Builder(wrapper) .setBackgroundColor(mThemeColor) .setOverlayDrawable(mOverlayDrawable) .setIconSize(iconSize) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java index 147f5e30f9d6..4dae63485f8c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java @@ -137,24 +137,11 @@ public class StartingSurfaceDrawer { private final SparseArray<SurfaceControlViewHost> mAnimatedSplashScreenSurfaceHosts = new SparseArray<>(1); - /** Obtain proper context for showing splash screen on the provided display. */ - private Context getDisplayContext(Context context, int displayId) { - if (displayId == DEFAULT_DISPLAY) { - // The default context fits. - return context; - } - - final Display targetDisplay = mDisplayManager.getDisplay(displayId); - if (targetDisplay == null) { - // Failed to obtain the non-default display where splash screen should be shown, - // lets not show at all. - return null; - } - - return context.createDisplayContext(targetDisplay); + private Display getDisplay(int displayId) { + return mDisplayManager.getDisplay(displayId); } - private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) { + int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) { return splashScreenThemeResId != 0 ? splashScreenThemeResId : activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource() @@ -177,7 +164,7 @@ public class StartingSurfaceDrawer { final int displayId = taskInfo.displayId; final int taskId = taskInfo.taskId; - Context context = mContext; + // replace with the default theme if the application didn't set final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo); if (DEBUG_SPLASH_SCREEN) { @@ -186,13 +173,16 @@ public class StartingSurfaceDrawer { + " suggestType=" + suggestType); } - // Obtain proper context to launch on the right display. - final Context displayContext = getDisplayContext(context, displayId); - if (displayContext == null) { + final Display display = getDisplay(displayId); + if (display == null) { // Can't show splash screen on requested display, so skip showing at all. return; } - context = displayContext; + Context context = displayId == DEFAULT_DISPLAY + ? mContext : mContext.createDisplayContext(display); + if (context == null) { + return; + } if (theme != context.getThemeResId()) { try { context = context.createPackageContextAsUser(activityInfo.packageName, @@ -303,7 +293,8 @@ public class StartingSurfaceDrawer { // Record whether create splash screen view success, notify to current thread after // create splash screen view finished. final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier(); - final FrameLayout rootLayout = new FrameLayout(context); + final FrameLayout rootLayout = new FrameLayout( + mSplashscreenContentDrawer.createViewContextWrapper(context)); rootLayout.setPadding(0, 0, 0, 0); rootLayout.setFitsSystemWindows(false); final Runnable setViewSynchronized = () -> { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java index eef0d9bb268f..18b8faf4dbe6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -101,7 +102,6 @@ public class StartingSurfaceDrawerTests { static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{ int mAddWindowForTask = 0; - int mViewThemeResId; TestStartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor, TransactionPool pool) { @@ -113,7 +113,6 @@ public class StartingSurfaceDrawerTests { View view, WindowManager wm, WindowManager.LayoutParams params, int suggestType) { // listen for addView mAddWindowForTask = taskId; - mViewThemeResId = view.getContext().getThemeResId(); // Do not wait for background color return false; } @@ -183,12 +182,15 @@ public class StartingSurfaceDrawerTests { final int taskId = 1; final StartingWindowInfo windowInfo = createWindowInfo(taskId, 0); + final int[] theme = new int[1]; + doAnswer(invocation -> theme[0] = (Integer) invocation.callRealMethod()) + .when(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any()); + mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder, STARTING_WINDOW_TYPE_SPLASH_SCREEN); waitHandlerIdle(mTestHandler); - verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(), - eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN)); - assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0); + verify(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any()); + assertNotEquals(theme[0], 0); } @Test diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index d17c32817994..8150e78fdddc 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -686,6 +686,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, std::unordered_set<uint32_t> finalized_ids; const auto lib_alias = child_chunk.header<ResTable_staged_alias_header>(); if (!lib_alias) { + LOG(ERROR) << "RES_TABLE_STAGED_ALIAS_TYPE is too small."; + return {}; + } + if ((child_chunk.data_size() / sizeof(ResTable_staged_alias_entry)) + < dtohl(lib_alias->count)) { + LOG(ERROR) << "RES_TABLE_STAGED_ALIAS_TYPE is too small to hold entries."; return {}; } const auto entry_begin = child_chunk.data_ptr().convert<ResTable_staged_alias_entry>(); diff --git a/libs/androidfw/OWNERS b/libs/androidfw/OWNERS index 38b642501fcd..17f5164cf417 100644 --- a/libs/androidfw/OWNERS +++ b/libs/androidfw/OWNERS @@ -1,4 +1,5 @@ set noparent +toddke@google.com zyy@google.com patb@google.com diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 48289ecde9e0..25b582d2fc8d 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -39,6 +39,7 @@ interface IMediaRouterService { MediaRouterClientState getState(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client); + void setBluetoothA2dpOn(IMediaRouterClient client, boolean on); void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 2986f7c75f4d..dfdfeacb065a 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -1070,7 +1070,8 @@ public class MediaRouter { && (types & ROUTE_TYPE_LIVE_AUDIO) != 0 && (route.isBluetooth() || route.isDefault())) { try { - sStatic.mAudioService.setBluetoothA2dpOn(route.isBluetooth()); + sStatic.mMediaRouterService.setBluetoothA2dpOn(sStatic.mClient, + route.isBluetooth()); } catch (RemoteException e) { Log.e(TAG, "Error changing Bluetooth A2DP state", e); } diff --git a/mms/OWNERS b/mms/OWNERS index f56845ed80c7..2e419c1e529c 100644 --- a/mms/OWNERS +++ b/mms/OWNERS @@ -3,6 +3,7 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com +amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com diff --git a/native/android/OWNERS b/native/android/OWNERS index 8b35f8d38691..02dfd393a0b7 100644 --- a/native/android/OWNERS +++ b/native/android/OWNERS @@ -1,7 +1,7 @@ jreck@google.com per-file libandroid_net.map.txt, net.c = set noparent -per-file libandroid_net.map.txt, net.c = jchalard@google.com, junyulai@google.com +per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS index b9de5a3919f5..a2352e20f841 100644 --- a/packages/CarrierDefaultApp/OWNERS +++ b/packages/CarrierDefaultApp/OWNERS @@ -2,6 +2,7 @@ set noparent tgunn@google.com breadley@google.com rgreenwalt@google.com +amitmahajan@google.com fionaxu@google.com jackyu@google.com jminjie@google.com diff --git a/packages/CtsShim/OWNERS b/packages/CtsShim/OWNERS index eb631bc7cbcf..94197715150d 100644 --- a/packages/CtsShim/OWNERS +++ b/packages/CtsShim/OWNERS @@ -1,2 +1,3 @@ ioffe@google.com +toddke@google.com patb@google.com
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 54230c8ef7c0..86604a2cd085 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -71,6 +71,7 @@ public class InfoMediaManager extends MediaManager { MediaRouter2Manager mRouterManager; @VisibleForTesting String mPackageName; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private MediaDevice mCurrentConnectedDevice; private LocalBluetoothManager mBluetoothManager; @@ -84,6 +85,9 @@ public class InfoMediaManager extends MediaManager { if (!TextUtils.isEmpty(packageName)) { mPackageName = packageName; } + + mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } @Override @@ -388,7 +392,9 @@ public class InfoMediaManager extends MediaManager { @TargetApi(Build.VERSION_CODES.R) boolean shouldEnableVolumeSeekBar(RoutingSessionInfo sessionInfo) { - return false; + return sessionInfo.isSystemSession() // System sessions are not remote + || mVolumeAdjustmentForRemoteGroupSessions + || sessionInfo.getSelectedRoutes().size() <= 1; } private void refreshDevices() { diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS index 80bb307749ed..177f86b08864 100644 --- a/packages/Shell/OWNERS +++ b/packages/Shell/OWNERS @@ -6,6 +6,7 @@ nandana@google.com svetoslavganov@google.com hackbod@google.com yamasani@google.com +toddke@google.com patb@google.com cbrubaker@google.com omakoto@google.com diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 918635d666fa..c88e95f07f12 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -323,6 +323,46 @@ </FrameLayout> </LinearLayout> + <LinearLayout + android:id="@+id/wifi_scan_notify_layout" + style="@style/InternetDialog.Network" + android:orientation="vertical" + android:layout_height="wrap_content" + android:paddingBottom="4dp" + android:clickable="false" + android:focusable="false"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minWidth="56dp" + android:gravity="start|top" + android:orientation="horizontal" + android:paddingEnd="12dp" + android:paddingTop="16dp" + android:paddingBottom="4dp"> + <ImageView + android:src="@drawable/ic_info_outline" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:tint="?android:attr/textColorTertiary"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:id="@+id/wifi_scan_notify_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="16dp" + android:paddingBottom="8dp" + android:textColor="?android:attr/textColorSecondary" + android:clickable="true"/> + </LinearLayout> + </LinearLayout> + <FrameLayout android:id="@+id/done_layout" android:layout_width="67dp" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 7aacb702b75a..4ad4fa9d0854 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3033,4 +3033,6 @@ <string name="see_all_networks">See all</string> <!-- Summary for warning to disconnect ethernet first then switch to other networks. [CHAR LIMIT=60] --> <string name="to_switch_networks_disconnect_ethernet">To switch networks, disconnect ethernet</string> + <!-- Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi scanning is on. [CHAR LIMIT=NONE] --> + <string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt index 9286175cc2ea..471bac16642b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt @@ -43,8 +43,7 @@ data class KeyguardFingerprintListenModel( val shouldListenForFingerprintAssistant: Boolean, val switchingUser: Boolean, val udfps: Boolean, - val userDoesNotHaveTrust: Boolean, - val userNeedsStrongAuth: Boolean + val userDoesNotHaveTrust: Boolean ) : KeyguardListenModel() { override val modality: Int = TYPE_FACE } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 877e76480b1e..7a518d2b2bfe 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2254,11 +2254,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab !(mFingerprintLockedOut && mBouncer && mCredentialAttempted); final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user); - final boolean userNeedsStrongAuth = userNeedsStrongAuth(); final boolean shouldListenUdfpsState = !isUdfps || (!userCanSkipBouncer && !isEncryptedOrLockdownForUser - && !userNeedsStrongAuth && userDoesNotHaveTrust && !mFingerprintLockedOut); @@ -2289,8 +2287,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab shouldListenForFingerprintAssistant, mSwitchingUser, isUdfps, - userDoesNotHaveTrust, - userNeedsStrongAuth)); + userDoesNotHaveTrust)); } return shouldListen; @@ -2394,7 +2391,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || (DEBUG_FINGERPRINT && model instanceof KeyguardFingerprintListenModel && mFingerprintRunningState != BIOMETRIC_STATE_RUNNING); - if (notYetRunning && model.getListening()) { + final boolean running = + (DEBUG_FACE + && model instanceof KeyguardFaceListenModel + && mFaceRunningState == BIOMETRIC_STATE_RUNNING) + || (DEBUG_FINGERPRINT + && model instanceof KeyguardFingerprintListenModel + && mFingerprintRunningState == BIOMETRIC_STATE_RUNNING); + if (notYetRunning && model.getListening() + || running && !model.getListening()) { mListenModels.add(model); } } diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java index e9c565377530..2c0b52638d2f 100644 --- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java +++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java @@ -496,6 +496,9 @@ public class ScreenDecorations extends SystemUI implements Tunable { lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS | WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; + // FLAG_SLIPPERY can only be set by trusted overlays + lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; + if (!DEBUG_SCREENSHOT_ROUNDED_CORNERS) { lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY; } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java index d8e80fe99331..0d7551ff66e9 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AnnotationLinkSpan.java @@ -30,7 +30,7 @@ import java.util.Optional; /** * A span that turns the text wrapped by annotation tag into the clickable link text. */ -class AnnotationLinkSpan extends ClickableSpan { +public class AnnotationLinkSpan extends ClickableSpan { private final Optional<View.OnClickListener> mClickListener; private AnnotationLinkSpan(View.OnClickListener listener) { @@ -50,7 +50,7 @@ class AnnotationLinkSpan extends ClickableSpan { * @param linkInfos used to attach the click action into the corresponding span * @return the text attached with the span */ - static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { + public static CharSequence linkify(CharSequence text, LinkInfo... linkInfos) { final SpannableString msg = new SpannableString(text); final Annotation[] spans = msg.getSpans(/* queryStart= */ 0, msg.length(), Annotation.class); @@ -78,12 +78,12 @@ class AnnotationLinkSpan extends ClickableSpan { /** * Data class to store the annotation and the click action. */ - static class LinkInfo { - static final String DEFAULT_ANNOTATION = "link"; + public static class LinkInfo { + public static final String DEFAULT_ANNOTATION = "link"; private final Optional<String> mAnnotation; private final Optional<View.OnClickListener> mListener; - LinkInfo(@NonNull String annotation, View.OnClickListener listener) { + public LinkInfo(@NonNull String annotation, View.OnClickListener listener) { mAnnotation = Optional.of(annotation); mListener = Optional.ofNullable(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java index 37a6cfaabb5e..0a9329845b23 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java @@ -330,7 +330,7 @@ public class BrightLineFalsingManager implements FalsingManager { || mTestHarness || mDataProvider.isJustUnlockedWithFace() || mDataProvider.isDocked() - || mAccessibilityManager.isEnabled(); + || mAccessibilityManager.isTouchExplorationEnabled(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt index d3d6e03c9bc7..6f30ac3901e1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt @@ -18,6 +18,7 @@ package com.android.systemui.controls.ui import android.annotation.MainThread import android.app.Dialog +import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -88,7 +89,7 @@ class ControlActionCoordinatorImpl @Inject constructor( bouncerOrRun(createAction(cvh.cws.ci.controlId, { cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK) if (cvh.usePanel()) { - showDetail(cvh, control.getAppIntent().getIntent()) + showDetail(cvh, control.getAppIntent()) } else { cvh.action(CommandAction(templateId)) } @@ -116,7 +117,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - showDetail(cvh, it.getAppIntent().getIntent()) + showDetail(cvh, it.getAppIntent()) } }, false /* blockable */)) } @@ -167,10 +168,10 @@ class ControlActionCoordinatorImpl @Inject constructor( bgExecutor.execute { vibrator.vibrate(effect) } } - private fun showDetail(cvh: ControlViewHolder, intent: Intent) { + private fun showDetail(cvh: ControlViewHolder, pendingIntent: PendingIntent) { bgExecutor.execute { val activities: List<ResolveInfo> = context.packageManager.queryIntentActivities( - intent, + pendingIntent.getIntent(), PackageManager.MATCH_DEFAULT_ONLY ) @@ -178,7 +179,7 @@ class ControlActionCoordinatorImpl @Inject constructor( // make sure the intent is valid before attempting to open the dialog if (activities.isNotEmpty() && taskViewFactory.isPresent) { taskViewFactory.get().create(context, uiExecutor, { - dialog = DetailDialog(activityContext, it, intent, cvh).also { + dialog = DetailDialog(activityContext, it, pendingIntent, cvh).also { it.setOnDismissListener { _ -> dialog = null } it.show() } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index 8a47a36de8c4..4758ab04e2e5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -43,7 +43,7 @@ import com.android.wm.shell.TaskView class DetailDialog( val activityContext: Context?, val taskView: TaskView, - val intent: Intent, + val pendingIntent: PendingIntent, val cvh: ControlViewHolder ) : Dialog( activityContext ?: cvh.context, @@ -59,6 +59,14 @@ class DetailDialog( var detailTaskId = INVALID_TASK_ID + private val fillInIntent = Intent().apply { + putExtra(EXTRA_USE_PANEL, true) + + // Apply flags to make behaviour match documentLaunchMode=always. + addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) + addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + } + fun removeDetailTask() { if (detailTaskId == INVALID_TASK_ID) return ActivityTaskManager.getInstance().removeTask(detailTaskId) @@ -67,13 +75,6 @@ class DetailDialog( val stateCallback = object : TaskView.Listener { override fun onInitialized() { - val launchIntent = Intent(intent) - launchIntent.putExtra(EXTRA_USE_PANEL, true) - - // Apply flags to make behaviour match documentLaunchMode=always. - launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) - launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - val options = activityContext?.let { ActivityOptions.makeCustomAnimation( it, @@ -82,9 +83,8 @@ class DetailDialog( ) } ?: ActivityOptions.makeBasic() taskView.startActivity( - PendingIntent.getActivity(context, 0, launchIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), - null /* fillInIntent */, + pendingIntent, + fillInIntent, options, getTaskViewBounds() ) @@ -97,6 +97,9 @@ class DetailDialog( override fun onTaskCreated(taskId: Int, name: ComponentName?) { detailTaskId = taskId + requireViewById<ViewGroup>(R.id.controls_activity_view).apply { + setAlpha(1f) + } } override fun onReleased() { @@ -121,6 +124,7 @@ class DetailDialog( requireViewById<ViewGroup>(R.id.controls_activity_view).apply { addView(taskView) + setAlpha(0f) } requireViewById<ImageView>(R.id.control_detail_close).apply { @@ -134,7 +138,7 @@ class DetailDialog( removeDetailTask() dismiss() context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) - v.context.startActivity(intent) + pendingIntent.send() } } diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java index b2def7a8596a..802e5ebaf1c7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java @@ -75,6 +75,7 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { private final ActivityStarter mActivityStarter; private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>(); private final boolean mAboveStatusbar; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private final NotificationEntryManager mNotificationEntryManager; @VisibleForTesting final List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>(); @@ -104,6 +105,8 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { mLocalMediaManager = new LocalMediaManager(mContext, lbm, imm, packageName); mMetricLogger = new MediaOutputMetricLogger(mContext, mPackageName); mUiEventLogger = uiEventLogger; + mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } void start(@NonNull Callback cb) { @@ -466,7 +469,9 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback { } boolean isVolumeControlEnabled(@NonNull MediaDevice device) { - return !isActiveRemoteDevice(device); + // TODO(b/202500642): Also enable volume control for remote non-group sessions. + return !isActiveRemoteDevice(device) + || mVolumeAdjustmentForRemoteGroupSessions; } private final MediaController.Callback mCb = new MediaController.Callback() { diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 70c21e43b79a..2c6e77c2444b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -108,6 +108,7 @@ public class NavigationBarView extends FrameLayout implements private final int mNavColorSampleMargin; private final SysUiState mSysUiFlagContainer; + // The current view is one of mHorizontal or mVertical depending on the current configuration View mCurrentView = null; private View mVertical; private View mHorizontal; @@ -370,12 +371,6 @@ public class NavigationBarView extends FrameLayout implements } } - @Override - protected boolean onSetAlpha(int alpha) { - Log.e(TAG, "onSetAlpha", new Throwable()); - return super.onSetAlpha(alpha); - } - public void setAutoHideController(AutoHideController autoHideController) { mAutoHideController = autoHideController; } @@ -474,6 +469,18 @@ public class NavigationBarView extends FrameLayout implements return mCurrentView; } + /** + * Applies {@param consumer} to each of the nav bar views. + */ + public void forEachView(Consumer<View> consumer) { + if (mVertical != null) { + consumer.accept(mVertical); + } + if (mHorizontal != null) { + consumer.accept(mHorizontal); + } + } + public RotationButtonController getRotationButtonController() { return mRotationButtonController; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java index dc54e1b52f2e..d0271f72153e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -36,6 +36,7 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.text.Html; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; @@ -63,12 +64,15 @@ import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.wifitrackerlib.WifiEntry; import java.util.List; +import java.util.concurrent.Executor; /** * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks. @@ -82,6 +86,7 @@ public class InternetDialog extends SystemUIDialog implements static final long PROGRESS_DELAY_MS = 2000L; private final Handler mHandler; + private final Executor mBackgroundExecutor; private final LinearLayoutManager mLayoutManager; @VisibleForTesting @@ -110,6 +115,8 @@ public class InternetDialog extends SystemUIDialog implements private LinearLayout mTurnWifiOnLayout; private LinearLayout mEthernetLayout; private TextView mWifiToggleTitleText; + private LinearLayout mWifiScanNotifyLayout; + private TextView mWifiScanNotifyText; private LinearLayout mSeeAllLayout; private RecyclerView mWifiRecyclerView; private ImageView mConnectedWifiIcon; @@ -154,13 +161,14 @@ public class InternetDialog extends SystemUIDialog implements public InternetDialog(Context context, InternetDialogFactory internetDialogFactory, InternetDialogController internetDialogController, boolean canConfigMobileData, boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger, - @Main Handler handler) { + @Main Handler handler, @Background Executor executor) { super(context, R.style.Theme_SystemUI_Dialog_Internet); if (DEBUG) { Log.d(TAG, "Init InternetDialog"); } mContext = context; mHandler = handler; + mBackgroundExecutor = executor; mInternetDialogFactory = internetDialogFactory; mInternetDialogController = internetDialogController; mSubscriptionManager = mInternetDialogController.getSubscriptionManager(); @@ -220,6 +228,8 @@ public class InternetDialog extends SystemUIDialog implements mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout); mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout); mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title); + mWifiScanNotifyLayout = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); + mWifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout); mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon); mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title); @@ -293,7 +303,13 @@ public class InternetDialog extends SystemUIDialog implements dismiss(); } - void updateDialog() { + /** + * Update the internet dialog when receiving the callback. + * + * @param shouldUpdateMobileNetwork {@code true} for update the mobile network layout, + * otherwise {@code false}. + */ + void updateDialog(boolean shouldUpdateMobileNetwork) { if (DEBUG) { Log.d(TAG, "updateDialog"); } @@ -303,8 +319,10 @@ public class InternetDialog extends SystemUIDialog implements mInternetDialogSubTitle.setText(getSubtitleText()); } updateEthernet(); - setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular() - || mInternetDialogController.isCarrierNetworkActive()); + if (shouldUpdateMobileNetwork) { + setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular() + || mInternetDialogController.isCarrierNetworkActive()); + } if (!mCanConfigWifi) { return; @@ -313,8 +331,10 @@ public class InternetDialog extends SystemUIDialog implements showProgressBar(); final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked(); final boolean isWifiEnabled = mWifiManager.isWifiEnabled(); + final boolean isWifiScanEnabled = mInternetDialogController.isWifiScanEnabled(); updateWifiToggle(isWifiEnabled, isDeviceLocked); updateConnectedWifi(isWifiEnabled, isDeviceLocked); + updateWifiScanNotify(isWifiEnabled, isWifiScanEnabled, isDeviceLocked); final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0) ? View.GONE : View.VISIBLE; @@ -371,7 +391,13 @@ public class InternetDialog extends SystemUIDialog implements } else { mMobileSummaryText.setVisibility(View.GONE); } - mSignalIcon.setImageDrawable(getSignalStrengthDrawable()); + + mBackgroundExecutor.execute(() -> { + Drawable drawable = getSignalStrengthDrawable(); + mHandler.post(() -> { + mSignalIcon.setImageDrawable(drawable); + }); + }); mMobileTitleText.setTextAppearance(isCarrierNetworkConnected ? R.style.TextAppearance_InternetDialog_Active : R.style.TextAppearance_InternetDialog); @@ -411,6 +437,24 @@ public class InternetDialog extends SystemUIDialog implements mContext.getColor(R.color.connected_network_primary_color)); } + @MainThread + private void updateWifiScanNotify(boolean isWifiEnabled, boolean isWifiScanEnabled, + boolean isDeviceLocked) { + if (isWifiEnabled || !isWifiScanEnabled || isDeviceLocked) { + mWifiScanNotifyLayout.setVisibility(View.GONE); + return; + } + if (TextUtils.isEmpty(mWifiScanNotifyText.getText())) { + final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo( + AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION, + v -> mInternetDialogController.launchWifiScanningSetting()); + mWifiScanNotifyText.setText(AnnotationLinkSpan.linkify( + getContext().getText(R.string.wifi_scan_notify_message), linkInfo)); + mWifiScanNotifyText.setMovementMethod(LinkMovementMethod.getInstance()); + } + mWifiScanNotifyLayout.setVisibility(View.VISIBLE); + } + void onClickConnectedWifi() { if (mConnectedWifiEntry == null) { return; @@ -508,52 +552,57 @@ public class InternetDialog extends SystemUIDialog implements @Override public void onRefreshCarrierInfo() { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSimStateChanged() { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onLost(Network network) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSubscriptionsChanged(int defaultDataSubId) { mDefaultDataSubId = defaultDataSubId; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); + } + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onServiceStateChanged(ServiceState serviceState) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @WorkerThread public void onDataConnectionStateChanged(int state, int networkType) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onSignalStrengthsChanged(SignalStrength signalStrength) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) { - mHandler.post(() -> updateDialog()); + mHandler.post(() -> updateDialog(true /* shouldUpdateMobileNetwork */)); } @Override @@ -565,7 +614,7 @@ public class InternetDialog extends SystemUIDialog implements mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount); mHandler.post(() -> { mAdapter.notifyDataSetChanged(); - updateDialog(); + updateDialog(false /* shouldUpdateMobileNetwork */); }); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index aaba5efc92f6..67e34113bebb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -76,6 +76,7 @@ import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; import com.android.systemui.toast.SystemUIToast; @@ -103,6 +104,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private static final String TAG = "InternetDialogController"; private static final String ACTION_NETWORK_PROVIDER_SETTINGS = "android.settings.NETWORK_PROVIDER_SETTINGS"; + private static final String ACTION_WIFI_SCANNING_SETTINGS = + "android.settings.WIFI_SCANNING_SETTINGS"; private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); public static final int NO_CELL_DATA_TYPE_ICON = 0; @@ -147,6 +150,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private ConnectivityManager.NetworkCallback mConnectivityManagerNetworkCallback; private WindowManager mWindowManager; private ToastFactory mToastFactory; + private SignalDrawable mSignalDrawable; + private LocationController mLocationController; @VisibleForTesting static final float TOAST_PARAMS_HORIZONTAL_WEIGHT = 1.0f; @@ -196,7 +201,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, GlobalSettings globalSettings, KeyguardStateController keyguardStateController, WindowManager windowManager, ToastFactory toastFactory, @Background Handler workerHandler, - CarrierConfigTracker carrierConfigTracker) { + CarrierConfigTracker carrierConfigTracker, + LocationController locationController) { if (DEBUG) { Log.d(TAG, "Init InternetDialogController"); } @@ -223,6 +229,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mConnectivityManagerNetworkCallback = new DataConnectivityListener(); mWindowManager = windowManager; mToastFactory = toastFactory; + mSignalDrawable = new SignalDrawable(mContext); + mLocationController = locationController; } void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { @@ -429,10 +437,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, Drawable getSignalStrengthIcon(Context context, int level, int numLevels, int iconType, boolean cutOut) { - Log.d(TAG, "getSignalStrengthIcon"); - final SignalDrawable signalDrawable = new SignalDrawable(context); - signalDrawable.setLevel( - SignalDrawable.getState(level, numLevels, cutOut)); + mSignalDrawable.setLevel(SignalDrawable.getState(level, numLevels, cutOut)); // Make the network type drawable final Drawable networkDrawable = @@ -441,7 +446,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, : context.getResources().getDrawable(iconType, context.getTheme()); // Overlay the two drawables - final Drawable[] layers = {networkDrawable, signalDrawable}; + final Drawable[] layers = {networkDrawable, mSignalDrawable}; final int iconSize = context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); @@ -603,6 +608,13 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } } + void launchWifiScanningSetting() { + mCallback.dismissDialog(); + final Intent intent = new Intent(ACTION_WIFI_SCANNING_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); + } + void connectCarrierNetwork() { final MergedCarrierEntry mergedCarrierEntry = mAccessPointController.getMergedCarrierEntry(); @@ -780,6 +792,14 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, return false; } + @WorkerThread + boolean isWifiScanEnabled() { + if (!mLocationController.isLocationEnabled()) { + return false; + } + return mWifiManager.isScanAlwaysAvailable(); + } + static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { final ActivityStarter mActivityStarter; final WifiEntry mWifiEntry; @@ -883,7 +903,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, TelephonyCallback.DataConnectionStateListener, TelephonyCallback.DisplayInfoListener, TelephonyCallback.ServiceStateListener, - TelephonyCallback.SignalStrengthsListener { + TelephonyCallback.SignalStrengthsListener, + TelephonyCallback.UserMobileDataStateListener { @Override public void onServiceStateChanged(@NonNull ServiceState serviceState) { @@ -905,6 +926,11 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mTelephonyDisplayInfo = telephonyDisplayInfo; mCallback.onDisplayInfoChanged(telephonyDisplayInfo); } + + @Override + public void onUserMobileDataStateChanged(boolean enabled) { + mCallback.onUserMobileDataStateChanged(enabled); + } } private class InternetOnSubscriptionChangedListener @@ -1009,6 +1035,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, void onSignalStrengthsChanged(SignalStrength signalStrength); + void onUserMobileDataStateChanged(boolean enabled); + void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); void dismissDialog(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt index 11c6980678b1..ea5df17bca58 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt @@ -20,7 +20,9 @@ import android.os.Handler import android.util.Log import com.android.internal.logging.UiEventLogger import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main +import java.util.concurrent.Executor import javax.inject.Inject private const val TAG = "InternetDialogFactory" @@ -32,6 +34,7 @@ private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) @SysUISingleton class InternetDialogFactory @Inject constructor( @Main private val handler: Handler, + @Background private val executor: Executor, private val internetDialogController: InternetDialogController, private val context: Context, private val uiEventLogger: UiEventLogger @@ -49,7 +52,8 @@ class InternetDialogFactory @Inject constructor( return } else { internetDialog = InternetDialog(context, this, internetDialogController, - canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler) + canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler, + executor) internetDialog?.show() } } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt index c50365f1bf38..71c5fad5322e 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt @@ -15,7 +15,8 @@ import com.android.systemui.statusbar.phone.SystemUIDialog class SensorUseDialog( context: Context, val sensor: Int, - val clickListener: DialogInterface.OnClickListener + val clickListener: DialogInterface.OnClickListener, + val dismissListener: DialogInterface.OnDismissListener ) : SystemUIDialog(context) { // TODO move to onCreate (b/200815309) @@ -69,6 +70,8 @@ class SensorUseDialog( context.getString(com.android.internal.R.string .cancel), clickListener) + setOnDismissListener(dismissListener) + setCancelable(false) } } diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt index b0071d92481d..dae375ad7cc7 100644 --- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt @@ -50,7 +50,7 @@ class SensorUseStartedActivity @Inject constructor( private val keyguardStateController: KeyguardStateController, private val keyguardDismissUtil: KeyguardDismissUtil, @Background private val bgHandler: Handler -) : Activity(), DialogInterface.OnClickListener { +) : Activity(), DialogInterface.OnClickListener, DialogInterface.OnDismissListener { companion object { private val LOG_TAG = SensorUseStartedActivity::class.java.simpleName @@ -120,7 +120,7 @@ class SensorUseStartedActivity @Inject constructor( } } - mDialog = SensorUseDialog(this, sensor, this) + mDialog = SensorUseDialog(this, sensor, this, this) mDialog!!.show() } @@ -212,4 +212,8 @@ class SensorUseStartedActivity @Inject constructor( .suppressSensorPrivacyReminders(sensor, suppressed) } } + + override fun onDismiss(dialog: DialogInterface?) { + finish() + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 2c76cfeff733..67f51cb9ab43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -485,7 +485,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private void showBouncer() { if (mMode == MODE_SHOW_BOUNCER) { - mKeyguardViewController.showBouncer(false); + mKeyguardViewController.showBouncer(true); } mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */, false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 1e3e47b75d8a..e5119fec75c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -552,12 +552,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void onStartedWakingUp() { mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(false); - View currentView = getCurrentNavBarView(); - if (currentView != null) { - currentView.animate() - .alpha(1f) - .setDuration(NAV_BAR_CONTENT_FADE_DURATION) - .start(); + NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + if (navBarView != null) { + navBarView.forEachView(view -> + view.animate() + .alpha(1f) + .setDuration(NAV_BAR_CONTENT_FADE_DURATION) + .start()); } } @@ -565,12 +566,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void onStartedGoingToSleep() { mStatusBar.getNotificationShadeWindowView().getWindowInsetsController() .setAnimationsDisabled(true); - View currentView = getCurrentNavBarView(); - if (currentView != null) { - currentView.animate() - .alpha(0f) - .setDuration(NAV_BAR_CONTENT_FADE_DURATION) - .start(); + NavigationBarView navBarView = mStatusBar.getNavigationBarView(); + if (navBarView != null) { + navBarView.forEachView(view -> + view.animate() + .alpha(0f) + .setDuration(NAV_BAR_CONTENT_FADE_DURATION) + .start()); } } @@ -899,7 +901,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb @Override public boolean bouncerIsOrWillBeShowing() { - return mBouncer.isShowing() || mBouncer.getShowingSoon(); + return isBouncerShowing() || mBouncer.getShowingSoon(); } public boolean isFullscreenBouncer() { @@ -996,17 +998,6 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBar.onKeyguardViewManagerStatesUpdated(); } - /** - * Updates the visibility of the nav bar content views. - */ - private void updateNavigationBarContentVisibility(boolean navBarContentVisible) { - final NavigationBarView navBarView = mStatusBar.getNavigationBarView(); - if (navBarView != null && navBarView.getCurrentView() != null) { - final View currentView = navBarView.getCurrentView(); - currentView.setVisibility(navBarContentVisible ? View.VISIBLE : View.INVISIBLE); - } - } - private View getCurrentNavBarView() { final NavigationBarView navBarView = mStatusBar.getNavigationBarView(); return navBarView != null ? navBarView.getCurrentView() : null; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt index 143aaba648da..e3f4b03dc4f2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -145,22 +145,27 @@ class UnlockedScreenOffAnimationController @Inject constructor( .setDuration(duration.toLong()) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .alpha(1f) - .withEndAction { - aodUiAnimationPlaying = false + .setListener(object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator?) { + aodUiAnimationPlaying = false - // Lock the keyguard if it was waiting for the screen off animation to end. - keyguardViewMediatorLazy.get().maybeHandlePendingLock() + // Lock the keyguard if it was waiting for the screen off animation to end. + keyguardViewMediatorLazy.get().maybeHandlePendingLock() - // Tell the StatusBar to become keyguard for real - we waited on that since it - // is slow and would have caused the animation to jank. - statusBar.updateIsKeyguard() + // Tell the StatusBar to become keyguard for real - we waited on that since + // it is slow and would have caused the animation to jank. + statusBar.updateIsKeyguard() - // Run the callback given to us by the KeyguardVisibilityHelper. - after.run() + // Run the callback given to us by the KeyguardVisibilityHelper. + after.run() - // Done going to sleep, reset this flag. - decidedToAnimateGoingToSleep = null - } + // Done going to sleep, reset this flag. + decidedToAnimateGoingToSleep = null + + // We need to unset the listener. These are persistent for future animators + keyguardView.animate().setListener(null) + } + }) .start() } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java index e57059894786..cd6a77836304 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java @@ -33,7 +33,11 @@ import android.media.AudioManager; import android.media.AudioSystem; import android.media.IAudioService; import android.media.IVolumeController; +import android.media.MediaRoute2Info; +import android.media.MediaRouter2Manager; +import android.media.RoutingSessionInfo; import android.media.VolumePolicy; +import android.media.session.MediaController; import android.media.session.MediaController.PlaybackInfo; import android.media.session.MediaSession.Token; import android.net.Uri; @@ -71,6 +75,7 @@ import com.android.systemui.util.concurrency.ThreadFactory; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -118,6 +123,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final Context mContext; private final Looper mWorkerLooper; private final PackageManager mPackageManager; + private final MediaRouter2Manager mRouter2Manager; private final WakefulnessLifecycle mWakefulnessLifecycle; private AudioManager mAudio; private IAudioService mAudioService; @@ -179,6 +185,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa mWorkerLooper = theadFactory.buildLooperOnNewThread( VolumeDialogControllerImpl.class.getSimpleName()); mWorker = new W(mWorkerLooper); + mRouter2Manager = MediaRouter2Manager.getInstance(mContext); mMediaSessionsCallbacksW = new MediaSessionsCallbacks(mContext); mMediaSessions = createMediaSessions(mContext, mWorkerLooper, mMediaSessionsCallbacksW); mAudio = audioManager; @@ -1149,16 +1156,16 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>(); private int mNextStream = DYNAMIC_STREAM_START_INDEX; - private final boolean mShowRemoteSessions; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; public MediaSessionsCallbacks(Context context) { - mShowRemoteSessions = context.getResources().getBoolean( - com.android.internal.R.bool.config_volumeShowRemoteSessions); + mVolumeAdjustmentForRemoteGroupSessions = context.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); } @Override public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) { - if (mShowRemoteSessions) { + if (showForSession(token)) { addStream(token, "onRemoteUpdate"); int stream = 0; @@ -1190,7 +1197,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa @Override public void onRemoteVolumeChanged(Token token, int flags) { - if (mShowRemoteSessions) { + if (showForSession(token)) { addStream(token, "onRemoteVolumeChanged"); int stream = 0; synchronized (mRemoteStreams) { @@ -1214,7 +1221,7 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa @Override public void onRemoteRemoved(Token token) { - if (mShowRemoteSessions) { + if (showForSession(token)) { int stream = 0; synchronized (mRemoteStreams) { if (!mRemoteStreams.containsKey(token)) { @@ -1233,14 +1240,41 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa } public void setStreamVolume(int stream, int level) { - if (mShowRemoteSessions) { - final Token t = findToken(stream); - if (t == null) { - Log.w(TAG, "setStreamVolume: No token found for stream: " + stream); - return; + final Token token = findToken(stream); + if (token == null) { + Log.w(TAG, "setStreamVolume: No token found for stream: " + stream); + return; + } + if (showForSession(token)) { + mMediaSessions.setVolume(token, level); + } + } + + private boolean showForSession(Token token) { + if (mVolumeAdjustmentForRemoteGroupSessions) { + return true; + } + MediaController ctr = new MediaController(mContext, token); + String packageName = ctr.getPackageName(); + List<RoutingSessionInfo> sessions = + mRouter2Manager.getRoutingSessions(packageName); + boolean foundNonSystemSession = false; + boolean isGroup = false; + for (RoutingSessionInfo session : sessions) { + if (!session.isSystemSession()) { + foundNonSystemSession = true; + int selectedRouteCount = session.getSelectedRoutes().size(); + if (selectedRouteCount > 1) { + isGroup = true; + break; + } } - mMediaSessions.setVolume(t, level); } + if (!foundNonSystemSession) { + Log.d(TAG, "No routing session for " + packageName); + return false; + } + return !isGroup; } private Token findToken(int stream) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt index db87c5df16e1..4bdab7658a06 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt @@ -75,8 +75,7 @@ private fun fingerprintModel(user: Int) = KeyguardFingerprintListenModel( shouldListenForFingerprintAssistant = false, switchingUser = false, udfps = false, - userDoesNotHaveTrust = false, - userNeedsStrongAuth = false + userDoesNotHaveTrust = false ) private fun faceModel(user: Int) = KeyguardFaceListenModel( diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index ec4dfba87af0..185a291f57ad 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -19,6 +19,7 @@ package com.android.keyguard; import static android.telephony.SubscriptionManager.DATA_ROAMING_DISABLE; import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID; +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.google.common.truth.Truth.assertThat; @@ -931,6 +932,19 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testStartUdfpsServiceStrongAuthRequiredAfterTimeout() { + // GIVEN status bar state is on the keyguard + mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD); + + // WHEN user loses smart unlock trust + when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser())) + .thenReturn(SOME_AUTH_REQUIRED_AFTER_USER_REQUEST); + + // THEN we should still listen for udfps + assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(true); + } + + @Test public void testShouldNotListenForUdfps_whenTrustEnabled() { // GIVEN a "we should listen for udfps" state mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java index c4f480d7e7aa..55ee433c8d9d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java @@ -91,7 +91,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesGesture() { assertThat(mBrightLineFalsingManager.isFalseTap(1)).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse(); } @@ -99,7 +99,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesTap() { assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse(); } @@ -107,7 +107,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase { @Test public void testA11yDisablesDoubleTap() { assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isTrue(); - when(mAccessibilityManager.isEnabled()).thenReturn(true); + when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(true); assertThat(mBrightLineFalsingManager.isFalseDoubleTap()).isFalse(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt new file mode 100644 index 000000000000..87b9172dcefc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.ui + +import android.app.PendingIntent +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.wm.shell.TaskView +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +@TestableLooper.RunWithLooper +class DetailDialogTest : SysuiTestCase() { + + @Mock + private lateinit var taskView: TaskView + @Mock + private lateinit var controlViewHolder: ControlViewHolder + @Mock + private lateinit var pendingIntent: PendingIntent + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun testPendingIntentIsUnModified() { + // GIVEN the dialog is created with a PendingIntent + val dialog = createDialog(pendingIntent) + + // WHEN the TaskView is initialized + dialog.stateCallback.onInitialized() + + // THEN the PendingIntent used to call startActivity is unmodified by systemui + verify(taskView).startActivity(eq(pendingIntent), any(), any(), any()) + } + + private fun createDialog(pendingIntent: PendingIntent): DetailDialog { + return DetailDialog( + mContext, + taskView, + pendingIntent, + controlViewHolder + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java index f9d5be6c4807..663edc7b373b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java @@ -49,6 +49,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.LocationController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; import com.android.systemui.toast.SystemUIToast; @@ -135,6 +136,8 @@ public class InternetDialogControllerTest extends SysuiTestCase { private Animator mAnimator; @Mock private CarrierConfigTracker mCarrierConfigTracker; + @Mock + private LocationController mLocationController; private TestableResources mTestableResources; private MockInternetDialogController mInternetDialogController; @@ -170,7 +173,8 @@ public class InternetDialogControllerTest extends SysuiTestCase { mSubscriptionManager, mTelephonyManager, mWifiManager, mock(ConnectivityManager.class), mHandler, mExecutor, mBroadcastDispatcher, mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController, - mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker); + mWindowManager, mToastFactory, mWorkerHandler, mCarrierConfigTracker, + mLocationController); mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, mInternetDialogController.mOnSubscriptionsChangedListener); mInternetDialogController.onStart(mInternetDialogCallback, true); @@ -602,6 +606,30 @@ public class InternetDialogControllerTest extends SysuiTestCase { verify(mMergedCarrierEntry).setEnabled(false); } + @Test + public void isWifiScanEnabled_locationOff_returnFalse() { + when(mLocationController.isLocationEnabled()).thenReturn(false); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + } + + @Test + public void isWifiScanEnabled_locationOn_returnIsScanAlwaysAvailable() { + when(mLocationController.isLocationEnabled()).thenReturn(true); + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isFalse(); + + when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); + + assertThat(mInternetDialogController.isWifiScanEnabled()).isTrue(); + } + private String getResourcesString(String name) { return mContext.getResources().getString(getResourcesId(name)); } @@ -625,12 +653,13 @@ public class InternetDialogControllerTest extends SysuiTestCase { KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings, KeyguardStateController keyguardStateController, WindowManager windowManager, ToastFactory toastFactory, Handler workerHandler, - CarrierConfigTracker carrierConfigTracker) { + CarrierConfigTracker carrierConfigTracker, + LocationController locationController) { super(context, uiEventLogger, starter, accessPointController, subscriptionManager, telephonyManager, wifiManager, connectivityManager, handler, mainExecutor, broadcastDispatcher, keyguardUpdateMonitor, globalSettings, keyguardStateController, windowManager, toastFactory, workerHandler, - carrierConfigTracker); + carrierConfigTracker, locationController); mGlobalSettings = globalSettings; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java index c42b64a09985..5e1fea512d55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -19,6 +19,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.View; import android.widget.LinearLayout; +import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; import androidx.test.filters.SmallTest; @@ -26,6 +27,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import com.android.wifitrackerlib.WifiEntry; import org.junit.After; @@ -64,6 +67,7 @@ public class InternetDialogTest extends SysuiTestCase { @Mock private InternetDialogController mInternetDialogController; + private FakeExecutor mBgExecutor = new FakeExecutor(new FakeSystemClock()); private InternetDialog mInternetDialog; private View mDialogView; private View mSubTitle; @@ -73,6 +77,7 @@ public class InternetDialogTest extends SysuiTestCase { private LinearLayout mConnectedWifi; private RecyclerView mWifiList; private LinearLayout mSeeAll; + private LinearLayout mWifiScanNotify; @Before public void setUp() { @@ -91,7 +96,8 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager); mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class), - mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler); + mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler, + mBgExecutor); mInternetDialog.mAdapter = mInternetAdapter; mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry); mInternetDialog.show(); @@ -104,6 +110,7 @@ public class InternetDialogTest extends SysuiTestCase { mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout); mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout); mSeeAll = mDialogView.requireViewById(R.id.see_all_layout); + mWifiScanNotify = mDialogView.requireViewById(R.id.wifi_scan_notify_layout); } @After @@ -126,7 +133,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOn_internetDialogSubTitleGone() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE); } @@ -135,7 +142,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOff_internetDialogSubTitleVisible() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE); } @@ -145,7 +152,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); when(mInternetDialogController.hasEthernet()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); } @@ -155,7 +162,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); when(mInternetDialogController.hasEthernet()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); } @@ -165,7 +172,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); when(mInternetDialogController.hasEthernet()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); } @@ -175,7 +182,7 @@ public class InternetDialogTest extends SysuiTestCase { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); when(mInternetDialogController.hasEthernet()).thenReturn(false); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); } @@ -184,7 +191,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_withApmOn_mobileDataLayoutGone() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(true); assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE); } @@ -194,7 +201,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.VISIBLE); } @@ -205,7 +212,7 @@ public class InternetDialogTest extends SysuiTestCase { mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/); doReturn(false).when(mInternetDialogController).activeNetworkIsCellular(); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); } @@ -215,7 +222,7 @@ public class InternetDialogTest extends SysuiTestCase { // The precondition WiFi ON is already in setUp() mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); @@ -225,7 +232,7 @@ public class InternetDialogTest extends SysuiTestCase { public void updateDialog_wifiOnAndHasWifiList_showWifiListAndSeeAll() { // The preconditions WiFi ON and WiFi entries are already in setUp() - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.VISIBLE); @@ -236,7 +243,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiToggle.getVisibility()).isEqualTo(View.VISIBLE); assertThat(mWifiToggle.getBackground()).isNotNull(); @@ -247,7 +254,7 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi ON and Internet WiFi are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE); } @@ -257,13 +264,57 @@ public class InternetDialogTest extends SysuiTestCase { // The preconditions WiFi entries are already in setUp() when(mInternetDialogController.isDeviceLocked()).thenReturn(true); - mInternetDialog.updateDialog(); + mInternetDialog.updateDialog(false); assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE); assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE); } @Test + public void updateDialog_wifiOn_hideWifiScanNotify() { + // The preconditions WiFi ON and Internet WiFi are already in setUp() + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOff_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(false); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceLocked_hideWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(true); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_wifiOffAndWifiScanOnAndDeviceUnlocked_showWifiScanNotify() { + when(mWifiManager.isWifiEnabled()).thenReturn(false); + when(mInternetDialogController.isWifiScanEnabled()).thenReturn(true); + when(mInternetDialogController.isDeviceLocked()).thenReturn(false); + + mInternetDialog.updateDialog(false); + + assertThat(mWifiScanNotify.getVisibility()).isEqualTo(View.VISIBLE); + TextView wifiScanNotifyText = mDialogView.requireViewById(R.id.wifi_scan_notify_text); + assertThat(wifiScanNotifyText.getText().length()).isNotEqualTo(0); + assertThat(wifiScanNotifyText.getMovementMethod()).isNotNull(); + } + + @Test public void onClickSeeMoreButton_clickSeeAll_verifyLaunchNetworkSetting() { mSeeAll.performClick(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index 4276f7ce7b12..25fd80133897 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -134,7 +134,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { .thenReturn(false); mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FINGERPRINT, true /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager).showBouncer(eq(false)); + verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean()); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER); @@ -146,7 +146,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { .thenReturn(false); mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT, BiometricSourceType.FINGERPRINT, false /* isStrongBiometric */); - verify(mStatusBarKeyguardViewManager).showBouncer(eq(false)); + verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); verify(mShadeController).animateCollapsePanels(anyInt(), anyBoolean(), anyBoolean(), anyFloat()); assertThat(mBiometricUnlockController.getMode()) @@ -265,10 +265,10 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { BiometricSourceType.FACE, true /* isStrongBiometric */); // Wake up before showing the bouncer - verify(mStatusBarKeyguardViewManager, never()).showBouncer(eq(false)); + verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean()); mBiometricUnlockController.mWakefulnessObserver.onFinishedWakingUp(); - verify(mStatusBarKeyguardViewManager).showBouncer(eq(false)); + verify(mStatusBarKeyguardViewManager).showBouncer(anyBoolean()); assertThat(mBiometricUnlockController.getMode()) .isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 2b569f31e916..5ed69853e40f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -102,6 +102,8 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { @Mock private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; @Mock + private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor; + @Mock private KeyguardMessageArea mKeyguardMessageArea; private WakefulnessLifecycle mWakefulnessLifecycle; @@ -287,6 +289,24 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { } @Test + public void testShowing_whenAlternateAuthShowing() { + mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); + when(mBouncer.isShowing()).thenReturn(false); + when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); + assertTrue("Is showing not accurate when alternative auth showing", + mStatusBarKeyguardViewManager.isShowing()); + } + + @Test + public void testWillBeShowing_whenAlternateAuthShowing() { + mStatusBarKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); + when(mBouncer.isShowing()).thenReturn(false); + when(mAlternateAuthInterceptor.isShowingAlternateAuthBouncer()).thenReturn(true); + assertTrue("Is or will be showing not accurate when alternative auth showing", + mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()); + } + + @Test public void testUpdateResources_delegatesToBouncer() { mStatusBarKeyguardViewManager.updateResources(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java index 5c0efd36fcd1..c9462d651bc0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java @@ -101,6 +101,11 @@ public class VolumeDialogControllerImplTest extends SysuiTestCase { // Initial non-set value when(mRingerModeLiveData.getValue()).thenReturn(-1); when(mRingerModeInternalLiveData.getValue()).thenReturn(-1); + // Enable group volume adjustments + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions, + true); + mCallback = mock(VolumeDialogControllerImpl.C.class); mThreadFactory.setLooper(TestableLooper.get(this).getLooper()); mVolumeController = new TestableVolumeDialogControllerImpl(mContext, diff --git a/proto/src/metrics_constants/OWNERS b/proto/src/metrics_constants/OWNERS index 274d0d6323cf..7009282b66e1 100644 --- a/proto/src/metrics_constants/OWNERS +++ b/proto/src/metrics_constants/OWNERS @@ -1,3 +1,4 @@ cwren@android.com yanglu@google.com yaochen@google.com +yro@google.com diff --git a/services/OWNERS b/services/OWNERS index 9b5f0e701fdf..67cee5517913 100644 --- a/services/OWNERS +++ b/services/OWNERS @@ -3,7 +3,7 @@ per-file Android.bp = file:platform/build/soong:/OWNERS # art-team@ manages the system server profile per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com -per-file java/com/android/server/* = patb@google.com +per-file java/com/android/server/* = toddke@google.com,patb@google.com per-file tests/servicestests/src/com/android/server/systemconfig/* = patb@google.com per-file proguard.flags = jdduke@google.com diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 8a42ddfdc19d..757f1aeb275f 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -1072,26 +1072,18 @@ public final class ContentCaptureManagerService extends ParcelFileDescriptor sourceOut = servicePipe.second; ParcelFileDescriptor sinkOut = servicePipe.first; - mParentService.mPackagesWithShareRequests.add(mDataShareRequest.getPackageName()); - - try { - mClientAdapter.write(sourceIn); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to call write() the client operation", e); - sendErrorSignal(mClientAdapter, serviceAdapter, - ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN); - logServiceEvent( - CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL); - return; + synchronized (mParentService.mLock) { + mParentService.mPackagesWithShareRequests.add(mDataShareRequest.getPackageName()); } - try { - serviceAdapter.start(sinkOut); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to call start() the service operation", e); + + if (!setUpSharingPipeline(mClientAdapter, serviceAdapter, sourceIn, sinkOut)) { sendErrorSignal(mClientAdapter, serviceAdapter, ContentCaptureManager.DATA_SHARE_ERROR_UNKNOWN); - logServiceEvent( - CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL); + bestEffortCloseFileDescriptors(sourceIn, sinkIn, sourceOut, sinkOut); + synchronized (mParentService.mLock) { + mParentService.mPackagesWithShareRequests + .remove(mDataShareRequest.getPackageName()); + } return; } @@ -1184,6 +1176,32 @@ public final class ContentCaptureManagerService extends } } + private boolean setUpSharingPipeline( + IDataShareWriteAdapter clientAdapter, + IDataShareReadAdapter serviceAdapter, + ParcelFileDescriptor sourceIn, + ParcelFileDescriptor sinkOut) { + try { + clientAdapter.write(sourceIn); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to call write() the client operation", e); + logServiceEvent( + CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_CLIENT_PIPE_FAIL); + return false; + } + + try { + serviceAdapter.start(sinkOut); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to call start() the service operation", e); + logServiceEvent( + CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__DATA_SHARE_ERROR_SERVICE_PIPE_FAIL); + return false; + } + + return true; + } + private void enforceDataSharingTtl(ParcelFileDescriptor sourceIn, ParcelFileDescriptor sinkIn, ParcelFileDescriptor sourceOut, diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index a5cfc4a62c96..c4efbd7e8f51 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -19,6 +19,7 @@ ogunwale@google.com # Permissions & Packages svetoslavganov@google.com +toddke@google.com patb@google.com # Battery Stats diff --git a/services/core/java/com/android/server/devicestate/OWNERS b/services/core/java/com/android/server/devicestate/OWNERS index 7708505ae2dd..ae79fc0e2c2d 100644 --- a/services/core/java/com/android/server/devicestate/OWNERS +++ b/services/core/java/com/android/server/devicestate/OWNERS @@ -1,2 +1,3 @@ ogunwale@google.com akulian@google.com +darryljohnson@google.com diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 3e52f5e07e62..5b7f5c85c1bb 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2837,7 +2837,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } final IBinder targetWindow = mImeTargetWindowMap.get(startInputToken); - if (targetWindow != null && mLastImeTargetWindow != targetWindow) { + if (targetWindow != null) { mWindowManagerInternal.updateInputMethodTargetWindow(token, targetWindow); } mLastImeTargetWindow = targetWindow; diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index a57d7db0ec54..7502afc8cd82 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -338,6 +338,25 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void setBluetoothA2dpOn(IMediaRouterClient client, boolean on) { + if (client == null) { + throw new IllegalArgumentException("client must not be null"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + mAudioService.setBluetoothA2dpOn(on); + } + } catch (RemoteException ex) { + Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn. on=" + on); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + // Binder call + @Override public void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan) { if (client == null) { diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 607218e20ea8..b424c2083bd4 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -146,6 +146,12 @@ public class MediaSession2Record implements MediaSessionRecordImpl { } @Override + public boolean canHandleVolumeKey() { + // TODO: Implement when MediaSession2 starts to get key events. + return false; + } + + @Override public int getSessionPolicies() { synchronized (mLock) { return mPolicies; diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 1525cd4da669..4822d6a62ac7 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -26,7 +26,9 @@ import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioSystem; import android.media.MediaMetadata; +import android.media.MediaRouter2Manager; import android.media.Rating; +import android.media.RoutingSessionInfo; import android.media.VolumeProvider; import android.media.session.ISession; import android.media.session.ISessionCallback; @@ -50,6 +52,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; @@ -121,6 +124,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR private final SessionCb mSessionCb; private final MediaSessionService mService; private final Context mContext; + private final boolean mVolumeAdjustmentForRemoteGroupSessions; private final Object mLock = new Object(); private final CopyOnWriteArrayList<ISessionControllerCallbackHolder> @@ -180,6 +184,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mAudioAttrs = DEFAULT_ATTRIBUTES; mPolicies = policies; + mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions); // May throw RemoteException if the session app is killed. mSessionCb.mCb.asBinder().linkToDeath(this, 0); @@ -285,35 +291,39 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR asSystemService, useSuggested, previousFlagPlaySound); } else { if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) { - // Nothing to do, the volume cannot be changed - return; - } - if (direction == AudioManager.ADJUST_TOGGLE_MUTE + if (DEBUG) { + Log.d(TAG, "Session does not support volume adjustment"); + } + } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE || direction == AudioManager.ADJUST_MUTE || direction == AudioManager.ADJUST_UNMUTE) { Log.w(TAG, "Muting remote playback is not supported"); - return; - } - if (DEBUG) { - Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService=" - + asSystemService + ", dir=" + direction); - } - mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction); + } else { + if (DEBUG) { + Log.w(TAG, "adjusting volume, pkg=" + packageName + ", asSystemService=" + + asSystemService + ", dir=" + direction); + } + mSessionCb.adjustVolume(packageName, pid, uid, asSystemService, direction); + + int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume); + mOptimisticVolume = volumeBefore + direction; + mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume)); + mHandler.removeCallbacks(mClearOptimisticVolumeRunnable); + mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT); + if (volumeBefore != mOptimisticVolume) { + pushVolumeUpdate(); + } - int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume); - mOptimisticVolume = volumeBefore + direction; - mOptimisticVolume = Math.max(0, Math.min(mOptimisticVolume, mMaxVolume)); - mHandler.removeCallbacks(mClearOptimisticVolumeRunnable); - mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT); - if (volumeBefore != mOptimisticVolume) { - pushVolumeUpdate(); + if (DEBUG) { + Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is " + + mMaxVolume); + } } + // Always notify, even if the volume hasn't changed. This is important to ensure that + // System UI receives an event if a hardware volume key is pressed but the session that + // handles it does not allow volume adjustment. Without such an event, System UI would + // not show volume controls to the user. mService.notifyRemoteVolumeChanged(flags, this); - - if (DEBUG) { - Log.d(TAG, "Adjusted optimistic volume to " + mOptimisticVolume + " max is " - + mMaxVolume); - } } } @@ -337,25 +347,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR }); } else { if (mVolumeControlType != VolumeProvider.VOLUME_CONTROL_ABSOLUTE) { - // Nothing to do. The volume can't be set directly. - return; - } - value = Math.max(0, Math.min(value, mMaxVolume)); - mSessionCb.setVolumeTo(packageName, pid, uid, value); + if (DEBUG) { + Log.d(TAG, "Session does not support setting volume"); + } + } else { + value = Math.max(0, Math.min(value, mMaxVolume)); + mSessionCb.setVolumeTo(packageName, pid, uid, value); + + int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume); + mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume)); + mHandler.removeCallbacks(mClearOptimisticVolumeRunnable); + mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT); + if (volumeBefore != mOptimisticVolume) { + pushVolumeUpdate(); + } - int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume); - mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume)); - mHandler.removeCallbacks(mClearOptimisticVolumeRunnable); - mHandler.postDelayed(mClearOptimisticVolumeRunnable, OPTIMISTIC_VOLUME_TIMEOUT); - if (volumeBefore != mOptimisticVolume) { - pushVolumeUpdate(); + if (DEBUG) { + Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is " + + mMaxVolume); + } } + // Always notify, even if the volume hasn't changed. mService.notifyRemoteVolumeChanged(flags, this); - - if (DEBUG) { - Log.d(TAG, "Set optimistic volume to " + mOptimisticVolume + " max is " - + mMaxVolume); - } } } @@ -449,6 +462,33 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } @Override + public boolean canHandleVolumeKey() { + if (isPlaybackTypeLocal() || mVolumeAdjustmentForRemoteGroupSessions) { + return true; + } + MediaRouter2Manager mRouter2Manager = MediaRouter2Manager.getInstance(mContext); + List<RoutingSessionInfo> sessions = + mRouter2Manager.getRoutingSessions(mPackageName); + boolean foundNonSystemSession = false; + boolean isGroup = false; + for (RoutingSessionInfo session : sessions) { + if (!session.isSystemSession()) { + foundNonSystemSession = true; + int selectedRouteCount = session.getSelectedRoutes().size(); + if (selectedRouteCount > 1) { + isGroup = true; + break; + } + } + } + if (!foundNonSystemSession) { + Log.d(TAG, "No routing session for " + mPackageName); + return false; + } + return !isGroup; + } + + @Override public int getSessionPolicies() { synchronized (mLock) { return mPolicies; diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java index 3c50597b8cfc..8f01f02f2ab1 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -131,6 +131,13 @@ public interface MediaSessionRecordImpl extends AutoCloseable { KeyEvent ke, int sequenceId, ResultReceiver cb); /** + * Returns whether the media session can handle volume key events. + * + * @return True if this media session can handle volume key events, false otherwise. + */ + boolean canHandleVolumeKey(); + + /** * Get session policies from custom policy provider set when MediaSessionRecord is instantiated. * If custom policy does not exist, will return null. */ diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java index c4c21df746b3..b75ba75e028b 100644 --- a/services/core/java/com/android/server/media/MediaSessionStack.java +++ b/services/core/java/com/android/server/media/MediaSessionStack.java @@ -325,8 +325,7 @@ class MediaSessionStack { int size = records.size(); for (int i = 0; i < size; i++) { MediaSessionRecord record = records.get(i); - // Do not send the volume key events to remote sessions. - if (record.checkPlaybackActiveState(true) && record.isPlaybackTypeLocal()) { + if (record.checkPlaybackActiveState(true) && record.canHandleVolumeKey()) { mCachedVolumeDefault = record; return record; } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 27b164830572..ee0b3d52eb3d 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -71,6 +71,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; @@ -81,7 +82,6 @@ import com.android.server.FgThread; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.SystemService; - import com.android.server.pm.UserManagerService; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -285,6 +285,12 @@ public final class OverlayManagerService extends SystemService { restoreSettings(); + // Wipe all shell overlays on boot, to recover from a potentially broken device + String shellPkgName = TextUtils.emptyIfNull( + getContext().getString(android.R.string.config_systemShell)); + mSettings.removeIf(overlayInfo -> overlayInfo.isFabricated + && shellPkgName.equals(overlayInfo.packageName)); + initIfNeeded(); onSwitchUser(UserHandle.USER_SYSTEM); @@ -891,6 +897,16 @@ public final class OverlayManagerService extends SystemService { throw new IllegalArgumentException(request.typeToString() + " unsupported for user " + request.userId); } + + // Normal apps are blocked from accessing OMS via SELinux, so to block non-root, + // non privileged callers, a simple check against the shell UID is sufficient, since + // that's the only exception from the other categories. This is enough while OMS + // is not a public API, but this will have to be changed if it's ever exposed. + if (callingUid == Process.SHELL_UID) { + EventLog.writeEvent(0x534e4554, "202768292", -1, ""); + throw new IllegalArgumentException("Non-root shell cannot fabricate overlays"); + } + realUserId = UserHandle.USER_ALL; // Enforce that the calling process can only register and unregister fabricated diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 00e54b1f6846..99f4a595ae8f 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -135,6 +135,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50; /** Upper bound on number of historical sessions for a UID */ private static final long MAX_HISTORICAL_SESSIONS = 1048576; + /** Destroy sessions older than this on storage free request */ + private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS; /** * Allow verification-skipping if it's a development app installed through ADB with @@ -338,22 +340,28 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @GuardedBy("mSessions") private void reconcileStagesLocked(String volumeUuid) { - final File stagingDir = getTmpSessionDir(volumeUuid); - final ArraySet<File> unclaimedStages = newArraySet( - stagingDir.listFiles(sStageFilter)); - - // We also need to clean up orphaned staging directory for staged sessions - final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid); - unclaimedStages.addAll(newArraySet(stagedSessionStagingDir.listFiles())); - + final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid); // Ignore stages claimed by active sessions for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); unclaimedStages.remove(session.stageDir); } + removeStagingDirs(unclaimedStages); + } + + private ArraySet<File> getStagingDirsOnVolume(String volumeUuid) { + final File stagingDir = getTmpSessionDir(volumeUuid); + final ArraySet<File> stagingDirs = newArraySet(stagingDir.listFiles(sStageFilter)); + + // We also need to clean up orphaned staging directory for staged sessions + final File stagedSessionStagingDir = Environment.getDataStagingDirectory(volumeUuid); + stagingDirs.addAll(newArraySet(stagedSessionStagingDir.listFiles())); + return stagingDirs; + } + private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) { // Clean up orphaned staging directories - for (File stage : unclaimedStages) { + for (File stage : stagingDirsToRemove) { Slog.w(TAG, "Deleting orphan stage " + stage); synchronized (mPm.mInstallLock) { mPm.removeCodePathLI(stage); @@ -367,6 +375,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + /** + * Called to free up some storage space from obsolete installation files + */ + public void freeStageDirs(String volumeUuid) { + final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid); + final long currentTimeMillis = System.currentTimeMillis(); + synchronized (mSessions) { + for (int i = 0; i < mSessions.size(); i++) { + final PackageInstallerSession session = mSessions.valueAt(i); + if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) { + // Only handles sessions stored on the target volume + continue; + } + final long age = currentTimeMillis - session.createdMillis; + if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) { + // Aggressively close old sessions because we are running low on storage + // Their staging dirs will be removed too + session.abandon(); + } else { + // Session is new enough, so it deserves to be kept even on low storage + unclaimedStagingDirsOnVolume.remove(session.stageDir); + } + } + } + removeStagingDirs(unclaimedStagingDirsOnVolume); + } + public static boolean isStageName(String name) { final boolean isFile = name.startsWith("vmdl") && name.endsWith(".tmp"); final boolean isContainer = name.startsWith("smdl") && name.endsWith(".tmp"); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 542948491dc8..d0e445749698 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -673,7 +673,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final Runnable r; synchronized (mLock) { assertNotChildLocked("StagedSession#abandon"); - assertCallerIsOwnerOrRoot(); + assertCallerIsOwnerOrRootOrSystem(); if (isInTerminalState()) { // We keep the session in the database if it's in a finalized state. It will be // removed by PackageInstallerService when the last update time is old enough. @@ -3704,7 +3704,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void abandonNonStaged() { synchronized (mLock) { assertNotChildLocked("abandonNonStaged"); - assertCallerIsOwnerOrRoot(); + assertCallerIsOwnerOrRootOrSystem(); if (mRelinquished) { if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control"); return; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3e0a7fdd51ef..bc28cffbcbfc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -9305,6 +9305,10 @@ public class PackageManagerService extends IPackageManager.Stub if (freeBytesRequired > 0) { smInternal.freeCache(volumeUuid, freeBytesRequired); } + + // 12. Clear temp install session files + mInstallerService.freeStageDirs(volumeUuid); + if (file.getUsableSpace() >= bytes) return; } else { try { diff --git a/services/core/java/com/android/server/pm/verify/domain/OWNERS b/services/core/java/com/android/server/pm/verify/domain/OWNERS index 445a8330037b..c669112e0512 100644 --- a/services/core/java/com/android/server/pm/verify/domain/OWNERS +++ b/services/core/java/com/android/server/pm/verify/domain/OWNERS @@ -2,3 +2,4 @@ chiuwinson@google.com patb@google.com +toddke@google.com
\ No newline at end of file diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index e05f7ef135fa..34a49ccd8040 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -4668,6 +4668,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { return mKeyguardDelegate.isInputRestricted(); } + /** {@inheritDoc} */ + @Override + public boolean isKeyguardUnoccluding() { + return keyguardOn() && !mWindowManagerFuncs.isAppTransitionStateIdle(); + } + @Override public void dismissKeyguardLw(IKeyguardDismissCallback callback, CharSequence message) { if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 78b03b2b88e7..510ab93e1af5 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -367,6 +367,12 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * as the top display. */ void moveDisplayToTop(int displayId); + + /** + * Return whether the app transition state is idle. + * @return {@code true} if app transition state is idle on the default display. + */ + boolean isAppTransitionStateIdle(); } /** @@ -974,6 +980,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { public boolean isKeyguardOccluded(); /** + * Return whether the keyguard is unoccluding. + * @return {@code true} if the keyguard is unoccluding. + */ + default boolean isKeyguardUnoccluding() { + return false; + } + + /** * @return true if in keyguard is on. */ boolean isKeyguardShowing(); diff --git a/services/core/java/com/android/server/stats/OWNERS b/services/core/java/com/android/server/stats/OWNERS index 2450dbb6bfcd..174ad3ad2e25 100644 --- a/services/core/java/com/android/server/stats/OWNERS +++ b/services/core/java/com/android/server/stats/OWNERS @@ -8,3 +8,4 @@ sharaienko@google.com singhtejinder@google.com tsaichristine@google.com yaochen@google.com +yro@google.com diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b52e527b0556..4520579e030a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1038,6 +1038,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" forceNewConfig="); pw.println(forceNewConfig); pw.print(prefix); pw.print("mActivityType="); pw.println(activityTypeToString(getActivityType())); + pw.print(prefix); pw.print("mImeInsetsFrozenUntilStartInput="); + pw.println(mImeInsetsFrozenUntilStartInput); if (requestedVrComponent != null) { pw.print(prefix); pw.print("requestedVrComponent="); diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index c1b287ff8077..c61cfeeac917 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -365,6 +365,10 @@ public class AppTransition implements Dump { setAppTransitionState(APP_STATE_IDLE); } + boolean isIdle() { + return mAppTransitionState == APP_STATE_IDLE; + } + boolean isTimeout() { return mAppTransitionState == APP_STATE_TIMEOUT; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 9335846e7805..bb8d6ef8fb12 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3969,11 +3969,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp * which controls the visibility and animation of the input method window. */ void updateImeInputAndControlTarget(WindowState target) { + if (target != null && target.mActivityRecord != null) { + target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; + } if (mImeInputTarget != target) { ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); - if (target != null && target.mActivityRecord != null) { - target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false; - } setImeInputTarget(target); updateImeControlTarget(); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index d0457b08aa34..b87d6f4fdf57 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -56,6 +56,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; +import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; @@ -848,6 +849,20 @@ public class DisplayPolicy { } /** + * Only trusted overlays are allowed to use FLAG_SLIPPERY. + */ + static int sanitizeFlagSlippery(int flags, int privateFlags, String name) { + if ((flags & FLAG_SLIPPERY) == 0) { + return flags; + } + if ((privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { + return flags; + } + Slog.w(TAG, "Removing FLAG_SLIPPERY for non-trusted overlay " + name); + return flags & ~FLAG_SLIPPERY; + } + + /** * Sanitize the layout parameters coming from a client. Allows the policy * to do things like ensure that windows of a specific type can't take * input focus. @@ -927,6 +942,8 @@ public class DisplayPolicy { if (mExtraNavBarAlt == win) { mExtraNavBarAltPosition = getAltBarPosition(attrs); } + + attrs.flags = sanitizeFlagSlippery(attrs.flags, attrs.privateFlags, win.getName()); } /** diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index bd688a618c63..52da4b80a75d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2125,6 +2125,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final Task rootTask; if (singleActivity) { rootTask = task; + + // Apply the last recents animation leash transform to the task entering PIP + rootTask.maybeApplyLastRecentsAnimationTransaction(); } else { // In the case of multiple activities, we will create a new task for it and then // move the PIP activity into the task. Note that we explicitly defer the task diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 4ff6d3c9a5f2..1f2a9a29932c 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -159,7 +159,8 @@ class WallpaperController { boolean needsShowWhenLockedWallpaper = false; if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 && mService.mPolicy.isKeyguardLocked() - && mService.mPolicy.isKeyguardOccluded()) { + && (mService.mPolicy.isKeyguardOccluded() + || mService.mPolicy.isKeyguardUnoccluding())) { // The lowest show when locked window decides whether we need to put the wallpaper // behind. needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs) diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 68e85c85b995..56bc1d80e9ec 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -56,6 +56,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; +import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY; import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE; import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; @@ -3081,6 +3082,11 @@ public class WindowManagerService extends IWindowManager.Stub syncInputTransactions(true /* waitForAnimations */); } + @Override + public boolean isAppTransitionStateIdle() { + return getDefaultDisplayContentLocked().mAppTransition.isIdle(); + } + /** * Notifies activity manager that some Keyguard flags have changed and that it needs to * reevaluate the visibilities of the activities. @@ -8267,8 +8273,10 @@ public class WindowManagerService extends IWindowManager.Stub h.token = channelToken; h.name = name; + flags = DisplayPolicy.sanitizeFlagSlippery(flags, privateFlags, name); + final int sanitizedFlags = flags & (LayoutParams.FLAG_NOT_TOUCHABLE - | LayoutParams.FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE); + | FLAG_SLIPPERY | LayoutParams.FLAG_NOT_FOCUSABLE); h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags; h.layoutParamsType = type; h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS; diff --git a/services/core/jni/stats/OWNERS b/services/core/jni/stats/OWNERS index 552cc0d31304..2611e5b6cee2 100644 --- a/services/core/jni/stats/OWNERS +++ b/services/core/jni/stats/OWNERS @@ -1,6 +1,8 @@ jeffreyhuang@google.com jtnguyen@google.com muhammadq@google.com +sharaieko@google.com singhtejinder@google.com tsaichristine@google.com yaochen@google.com +yro@google.com diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9ceabce398ed..0792d9bde4b4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -12648,6 +12648,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent( + @NonNull UserHandle userHandle) { + return DevicePolicyManagerService.this.getProfileOwnerOrDeviceOwnerSupervisionComponent( + userHandle); + } + + @Override public boolean isActiveDeviceOwner(int uid) { return isDeviceOwner(new CallerIdentity(uid, null, null)); } diff --git a/services/incremental/OWNERS b/services/incremental/OWNERS index fe8c253aa793..7ebb962c8feb 100644 --- a/services/incremental/OWNERS +++ b/services/incremental/OWNERS @@ -3,5 +3,6 @@ include /services/core/java/com/android/server/pm/OWNERS alexbuy@google.com schfan@google.com +toddke@google.com zyy@google.com patb@google.com diff --git a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java index 24c58f49bed6..7358551d1bc5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/usage/UserUsageStatsServiceTest.java @@ -72,7 +72,7 @@ public class UserUsageStatsServiceTest { HashMap<String, Long> installedPkgs = new HashMap<>(); installedPkgs.put(TEST_PACKAGE_NAME, System.currentTimeMillis()); - mService.init(System.currentTimeMillis(), installedPkgs); + mService.init(System.currentTimeMillis(), installedPkgs, true); } @After diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 6f04f176afd8..29fa2d379379 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -37,6 +37,7 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.os.Process.NOBODY_UID; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.InsetsState.ITYPE_IME; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; @@ -127,6 +128,8 @@ import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner.Stub; import android.view.IWindowManager; import android.view.IWindowSession; +import android.view.InsetsSource; +import android.view.InsetsState; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationTarget; import android.view.Surface; @@ -2884,6 +2887,41 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); } + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + + InsetsSource imeSource = new InsetsSource(ITYPE_IME); + app.getInsetsState().addSource(imeSource); + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.updateImeInputAndControlTarget(app); + + InsetsState state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app); + assertFalse(state.getSource(ITYPE_IME).isVisible()); + assertTrue(state.getSource(ITYPE_IME).getFrame().isEmpty()); + + // Simulate app is closing and expect IME insets is frozen. + mDisplayContent.mOpeningApps.clear(); + app.mActivityRecord.commitVisibility(false, false); + app.mActivityRecord.onWindowsGone(); + assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Simulate app re-start input or turning screen off/on then unlocked by un-secure + // keyguard to back to the app, expect IME insets is not frozen + imeSource.setFrame(new Rect(100, 400, 500, 500)); + app.getInsetsState().addSource(imeSource); + app.getInsetsState().setSourceVisible(ITYPE_IME, true); + mDisplayContent.updateImeInputAndControlTarget(app); + assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); + + // Verify when IME is visible and the app can receive the right IME insets from policy. + makeWindowVisibleAndDrawn(app, mImeWindow); + state = mDisplayContent.getInsetsPolicy().getInsetsForWindow(app); + assertTrue(state.getSource(ITYPE_IME).isVisible()); + assertEquals(state.getSource(ITYPE_IME).getFrame(), imeSource.getFrame()); + } + private void assertHasStartingWindow(ActivityRecord atoken) { assertNotNull(atoken.mStartingSurface); assertNotNull(atoken.mStartingData); diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 1b8492722c10..ac1fcce20dc0 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -380,6 +380,7 @@ public class UsageStatsService extends SystemService implements if (userId == UserHandle.USER_SYSTEM) { UsageStatsIdleService.scheduleUpdateMappingsJob(getContext()); } + final boolean deleteObsoleteData = shouldDeleteObsoleteData(UserHandle.of(userId)); synchronized (mLock) { // This should be safe to add this early. Other than reportEventOrAddToQueue, every // other user grabs the lock before accessing @@ -402,7 +403,7 @@ public class UsageStatsService extends SystemService implements boolean needToFlush = !pendingEvents.isEmpty(); initializeUserUsageStatsServiceLocked(userId, System.currentTimeMillis(), - installedPackages); + installedPackages, deleteObsoleteData); final UserUsageStatsService userService = getUserUsageStatsServiceLocked(userId); if (userService == null) { Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId); @@ -596,13 +597,13 @@ public class UsageStatsService extends SystemService implements * when the user is initially unlocked. */ private void initializeUserUsageStatsServiceLocked(int userId, long currentTimeMillis, - HashMap<String, Long> installedPackages) { + HashMap<String, Long> installedPackages, boolean deleteObsoleteData) { final File usageStatsDir = new File(Environment.getDataSystemCeDirectory(userId), "usagestats"); final UserUsageStatsService service = new UserUsageStatsService(getContext(), userId, usageStatsDir, this); try { - service.init(currentTimeMillis, installedPackages); + service.init(currentTimeMillis, installedPackages, deleteObsoleteData); mUserState.put(userId, service); } catch (Exception e) { if (mUserManager.isUserUnlocked(userId)) { @@ -1165,6 +1166,10 @@ public class UsageStatsService extends SystemService implements * Called by the Binder stub. */ private boolean updatePackageMappingsData() { + // don't update the mappings if a profile user is defined + if (!shouldDeleteObsoleteData(UserHandle.SYSTEM)) { + return true; // return true so job scheduler doesn't reschedule the job + } // fetch the installed packages outside the lock so it doesn't block package manager. final HashMap<String, Long> installedPkgs = getInstalledPackages(UserHandle.USER_SYSTEM); synchronized (mLock) { @@ -1309,6 +1314,13 @@ public class UsageStatsService extends SystemService implements } } + private boolean shouldDeleteObsoleteData(UserHandle userHandle) { + final DevicePolicyManagerInternal dpmInternal = getDpmInternal(); + // If a profile owner is not defined for the given user, obsolete data should be deleted + return dpmInternal == null + || dpmInternal.getProfileOwnerOrDeviceOwnerSupervisionComponent(userHandle) == null; + } + private String buildFullToken(String packageName, String token) { final StringBuilder sb = new StringBuilder(packageName.length() + token.length() + 1); sb.append(packageName); @@ -2532,8 +2544,12 @@ public class UsageStatsService extends SystemService implements private class MyPackageMonitor extends PackageMonitor { @Override public void onPackageRemoved(String packageName, int uid) { - mHandler.obtainMessage(MSG_PACKAGE_REMOVED, getChangingUserId(), 0, packageName) - .sendToTarget(); + final int changingUserId = getChangingUserId(); + // Only remove the package's data if a profile owner is not defined for the user + if (shouldDeleteObsoleteData(UserHandle.of(changingUserId))) { + mHandler.obtainMessage(MSG_PACKAGE_REMOVED, changingUserId, 0, packageName) + .sendToTarget(); + } super.onPackageRemoved(packageName, uid); } } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 36d8c857ca21..fee4a47fd6ff 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -115,8 +115,9 @@ class UserUsageStatsService { mSystemTimeSnapshot = System.currentTimeMillis(); } - void init(final long currentTimeMillis, HashMap<String, Long> installedPackages) { - readPackageMappingsLocked(installedPackages); + void init(final long currentTimeMillis, HashMap<String, Long> installedPackages, + boolean deleteObsoleteData) { + readPackageMappingsLocked(installedPackages, deleteObsoleteData); mDatabase.init(currentTimeMillis); if (mDatabase.wasUpgradePerformed()) { mDatabase.prunePackagesDataOnUpgrade(installedPackages); @@ -180,12 +181,13 @@ class UserUsageStatsService { return mDatabase.onPackageRemoved(packageName, timeRemoved); } - private void readPackageMappingsLocked(HashMap<String, Long> installedPackages) { + private void readPackageMappingsLocked(HashMap<String, Long> installedPackages, + boolean deleteObsoleteData) { mDatabase.readMappingsLocked(); // Package mappings for the system user are updated after 24 hours via a job scheduled by // UsageStatsIdleService to ensure restored data is not lost on first boot. Additionally, // this makes user service initialization a little quicker on subsequent boots. - if (mUserId != UserHandle.USER_SYSTEM) { + if (mUserId != UserHandle.USER_SYSTEM && deleteObsoleteData) { updatePackageMappingsLocked(installedPackages); } } diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java index 70d6aab542a2..889e182af46b 100644 --- a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java +++ b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java @@ -356,7 +356,7 @@ public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRec private void handleAirplaneModeEvent() { try { getVendorUwbAdapter().setEnabled(isEnabled()); - } catch (RemoteException e) { + } catch (RemoteException | IllegalStateException e) { Log.e(TAG, "Unable to set UWB Adapter state.", e); } } diff --git a/telephony/OWNERS b/telephony/OWNERS index 4016ba7de379..f248fd52db83 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -1,5 +1,6 @@ set noparent +amitmahajan@google.com breadley@google.com fionaxu@google.com jackyu@google.com diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 95b9fda34211..5851ee182368 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -964,6 +964,21 @@ public class CarrierConfigManager { = "carrier_use_ims_first_for_emergency_bool"; /** + * When {@code true}, the determination of whether to place a call as an emergency call will be + * based on the known {@link android.telephony.emergency.EmergencyNumber}s for the SIM on which + * the call is being placed. In a dual SIM scenario, if Sim A has the emergency numbers + * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, + * it will not be treated as an emergency call in this case. + * When {@code false}, the determination is based on the emergency numbers from all device SIMs, + * regardless of which SIM the call is being placed on. If Sim A has the emergency numbers + * 123, 456 and Sim B has the emergency numbers 789, and the user places a call on SIM A to 789, + * the call will be dialed as an emergency number, but with an unspecified routing. + * @hide + */ + public static final String KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL = + "use_only_dialed_sim_ecc_list_bool"; + + /** * When IMS instant lettering is available for a carrier (see * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines the list of characters * which may not be contained in messages. Should be specified as a regular expression suitable @@ -5339,6 +5354,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_IMS_GBA_REQUIRED_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false); sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true); + sDefaults.putBoolean(KEY_USE_ONLY_DIALED_SIM_ECC_LIST_BOOL, false); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, ""); diff --git a/tests/Codegen/OWNERS b/tests/Codegen/OWNERS index e69de29bb2d1..da723b3b67da 100644 --- a/tests/Codegen/OWNERS +++ b/tests/Codegen/OWNERS @@ -0,0 +1 @@ +eugenesusla@google.com
\ No newline at end of file diff --git a/tools/aapt2/OWNERS b/tools/aapt2/OWNERS index a96d15ea8233..4f655e54a7c2 100644 --- a/tools/aapt2/OWNERS +++ b/tools/aapt2/OWNERS @@ -1,3 +1,4 @@ set noparent +toddke@google.com zyy@google.com patb@google.com
\ No newline at end of file diff --git a/tools/codegen/OWNERS b/tools/codegen/OWNERS index e69de29bb2d1..da723b3b67da 100644 --- a/tools/codegen/OWNERS +++ b/tools/codegen/OWNERS @@ -0,0 +1 @@ +eugenesusla@google.com
\ No newline at end of file |