diff options
132 files changed, 1965 insertions, 693 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 4db1f71e8256..1397f5ea10dc 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2721,10 +2721,13 @@ class ContextImpl extends Context { // need to override their display in ResourcesManager. baseContext.mForceDisplayOverrideInResources = false; baseContext.mContextType = CONTEXT_TYPE_WINDOW_CONTEXT; - baseContext.mDisplay = display; final Resources windowContextResources = createWindowContextResources(baseContext); baseContext.setResources(windowContextResources); + // Associate the display with window context resources so that configuration update from + // the server side will also apply to the display's metrics. + baseContext.mDisplay = ResourcesManager.getInstance() + .getAdjustedDisplay(display.getDisplayId(), windowContextResources); return baseContext; } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 8d332ab1d58b..6cfa39cd2337 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -559,6 +559,53 @@ public class WallpaperManager { return null; } + public Rect peekWallpaperDimensions(Context context, boolean returnDefault, int userId) { + if (mService != null) { + try { + if (!mService.isWallpaperSupported(context.getOpPackageName())) { + return new Rect(); + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + Rect dimensions = null; + synchronized (this) { + try { + Bundle params = new Bundle(); + // Let's peek user wallpaper first. + ParcelFileDescriptor pfd = mService.getWallpaperWithFeature( + context.getOpPackageName(), context.getAttributionTag(), this, + FLAG_SYSTEM, params, userId); + if (pfd != null) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor(), null, options); + dimensions = new Rect(0, 0, options.outWidth, options.outHeight); + } + } catch (RemoteException ex) { + Log.w(TAG, "peek wallpaper dimensions failed", ex); + } + } + // If user wallpaper is unavailable, may be the default one instead. + if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0) + && returnDefault) { + InputStream is = openDefaultWallpaper(context, FLAG_SYSTEM); + if (is != null) { + try { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, options); + dimensions = new Rect(0, 0, options.outWidth, options.outHeight); + } finally { + IoUtils.closeQuietly(is); + } + } + } + return dimensions; + } + void forgetLoadedWallpaper() { synchronized (this) { mCachedWallpaper = null; @@ -1039,6 +1086,17 @@ public class WallpaperManager { } /** + * Peek the dimensions of system wallpaper of the user without decoding it. + * + * @return the dimensions of system wallpaper + * @hide + */ + public Rect peekBitmapDimensions() { + return sGlobals.peekWallpaperDimensions( + mContext, true /* returnDefault */, mContext.getUserId()); + } + + /** * Get an open, readable file descriptor to the given wallpaper image file. * The caller is responsible for closing the file descriptor when done ingesting the file. * diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index 063ba1174cdc..2e94dd1a47c4 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -143,7 +143,7 @@ public class AppWidgetProviderInfo implements Parcelable { public ComponentName provider; /** - * The default height of the widget when added to a host, in dp. The widget will get + * The default height of the widget when added to a host, in px. The widget will get * at least this width, and will often be given more, depending on the host. * * <p>This field corresponds to the <code>android:minWidth</code> attribute in @@ -152,7 +152,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minWidth; /** - * The default height of the widget when added to a host, in dp. The widget will get + * The default height of the widget when added to a host, in px. The widget will get * at least this height, and will often be given more, depending on the host. * * <p>This field corresponds to the <code>android:minHeight</code> attribute in @@ -161,7 +161,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minHeight; /** - * Minimum width (in dp) which the widget can be resized to. This field has no effect if it + * Minimum width (in px) which the widget can be resized to. This field has no effect if it * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}). * * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in @@ -170,7 +170,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minResizeWidth; /** - * Minimum height (in dp) which the widget can be resized to. This field has no effect if it + * Minimum height (in px) which the widget can be resized to. This field has no effect if it * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}). * * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in @@ -179,7 +179,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int minResizeHeight; /** - * Maximum width (in dp) which the widget can be resized to. This field has no effect if it is + * Maximum width (in px) which the widget can be resized to. This field has no effect if it is * smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}). * * <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the @@ -189,7 +189,7 @@ public class AppWidgetProviderInfo implements Parcelable { public int maxResizeWidth; /** - * Maximum height (in dp) which the widget can be resized to. This field has no effect if it is + * Maximum height (in px) which the widget can be resized to. This field has no effect if it is * smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}). * * <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 08e95a267d7f..c3ec09466de6 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5935,6 +5935,10 @@ public abstract class Context { * more general access to the URI's content provider then this check will * always fail. * + * <strong>Note:</strong> On SDK Version {@link android.os.Build.VERSION_CODES#S}, + * calling this method from a secondary-user's context will incorrectly return + * {@link PackageManager#PERMISSION_DENIED} for all {code uris}. + * * @param uris The list of URIs that is being checked. * @param pid The process ID being checked against. Must be > 0. * @param uid The user ID being checked against. A uid of 0 is the root diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index fc728a22ed5a..4708f3e0664f 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -104,6 +104,9 @@ public class CameraDeviceImpl extends CameraDevice private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>(); + /** map request IDs which have batchedOutputs to requestCount*/ + private HashMap<Integer, Integer> mBatchOutputMap = new HashMap<>(); + private int mRepeatingRequestId = REQUEST_ID_NONE; // Latest repeating request list's types private int[] mRepeatingRequestTypes; @@ -973,6 +976,7 @@ public class CameraDeviceImpl extends CameraDevice mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null); mIdle = true; mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>(); + mBatchOutputMap = new HashMap<>(); mFrameNumberTracker = new FrameNumberTracker(); mCurrentSession.closeWithoutDraining(); @@ -1179,6 +1183,41 @@ public class CameraDeviceImpl extends CameraDevice return requestTypes; } + private boolean hasBatchedOutputs(List<CaptureRequest> requestList) { + boolean hasBatchedOutputs = true; + for (int i = 0; i < requestList.size(); i++) { + CaptureRequest request = requestList.get(i); + if (!request.isPartOfCRequestList()) { + hasBatchedOutputs = false; + break; + } + if (i == 0) { + Collection<Surface> targets = request.getTargets(); + if (targets.size() != 2) { + hasBatchedOutputs = false; + break; + } + } + } + return hasBatchedOutputs; + } + + private void updateTracker(int requestId, long frameNumber, + int requestType, CaptureResult result, boolean isPartialResult) { + int requestCount = 1; + // If the request has batchedOutputs update each frame within the batch. + if (mBatchOutputMap.containsKey(requestId)) { + requestCount = mBatchOutputMap.get(requestId); + for (int i = 0; i < requestCount; i++) { + mFrameNumberTracker.updateTracker(frameNumber - (requestCount - 1 - i), + result, isPartialResult, requestType); + } + } else { + mFrameNumberTracker.updateTracker(frameNumber, result, + isPartialResult, requestType); + } + } + private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback, Executor executor, boolean repeating) throws CameraAccessException { @@ -1224,6 +1263,14 @@ public class CameraDeviceImpl extends CameraDevice request.recoverStreamIdToSurface(); } + // If the request has batched outputs, then store the + // requestCount and requestId in the map. + boolean hasBatchedOutputs = hasBatchedOutputs(requestList); + if (hasBatchedOutputs) { + int requestCount = requestList.size(); + mBatchOutputMap.put(requestInfo.getRequestId(), requestCount); + } + if (callback != null) { mCaptureCallbackMap.put(requestInfo.getRequestId(), new CaptureCallbackHolder( @@ -1839,8 +1886,18 @@ public class CameraDeviceImpl extends CameraDevice if (DEBUG) { Log.v(TAG, String.format("got error frame %d", frameNumber)); } - mFrameNumberTracker.updateTracker(frameNumber, - /*error*/true, request.getRequestType()); + + // Update FrameNumberTracker for every frame during HFR mode. + if (mBatchOutputMap.containsKey(requestId)) { + for (int i = 0; i < mBatchOutputMap.get(requestId); i++) { + mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i), + /*error*/true, request.getRequestType()); + } + } else { + mFrameNumberTracker.updateTracker(frameNumber, + /*error*/true, request.getRequestType()); + } + checkAndFireSequenceComplete(); // Dispatch the failure callback @@ -2023,7 +2080,6 @@ public class CameraDeviceImpl extends CameraDevice public void onResultReceived(CameraMetadataNative result, CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[]) throws RemoteException { - int requestId = resultExtras.getRequestId(); long frameNumber = resultExtras.getFrameNumber(); @@ -2064,8 +2120,8 @@ public class CameraDeviceImpl extends CameraDevice + frameNumber); } - mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, /*result*/null, + isPartialResult); return; } @@ -2077,8 +2133,9 @@ public class CameraDeviceImpl extends CameraDevice + frameNumber); } - mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, /*result*/null, + isPartialResult); + return; } @@ -2184,9 +2241,7 @@ public class CameraDeviceImpl extends CameraDevice Binder.restoreCallingIdentity(ident); } - // Collect the partials for a total result; or mark the frame as totally completed - mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, - requestType); + updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult); // Fire onCaptureSequenceCompleted if (!isPartialResult) { diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 431bf4c54b4b..217e17ddd7b4 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -258,6 +258,13 @@ public final class DeviceConfig { public static final String NAMESPACE_JOB_SCHEDULER = "jobscheduler"; /** + * Namespace for all lmkd related features. + * + * @hide + */ + public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native"; + + /** * Namespace for all location related features. * * @hide diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a55484b89177..00abc759278f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2242,6 +2242,21 @@ public final class Settings { public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS"; /** + * Activity Action: Show screen that lets user configure wifi tethering. + * <p> + * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + * <p> + * Input: Nothing + * <p> + * Output: Nothing + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_WIFI_TETHER_SETTING = + "com.android.settings.WIFI_TETHER_SETTINGS"; + + /** * Broadcast to trigger notification of asking user to enable MMS. * Need to specify {@link #EXTRA_ENABLE_MMS_DATA_REQUEST_REASON} and {@link #EXTRA_SUB_ID}. * diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 8e4a68e52697..40041486f6a6 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -436,7 +436,7 @@ public class StatusBarNotification implements Parcelable { try { ApplicationInfo ai = context.getPackageManager() .getApplicationInfoAsUser(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, - getUserId()); + getNormalizedUserId()); mContext = context.createApplicationContext(ai, Context.CONTEXT_RESTRICTED); } catch (PackageManager.NameNotFoundException e) { diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index f4770727e31f..c198a492d4c9 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -96,6 +96,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -152,6 +153,7 @@ public abstract class WallpaperService extends Service { private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050; private static final int MSG_ZOOM = 10100; private static final int MSG_SCALE_PREVIEW = 10110; + private static final int MSG_REPORT_SHOWN = 10150; private static final List<Float> PROHIBITED_STEPS = Arrays.asList(0f, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY); @@ -527,6 +529,35 @@ public abstract class WallpaperService extends Service { } /** + * This will be called in the end of {@link #updateSurface(boolean, boolean, boolean)}. + * If true is returned, the engine will not report shown until rendering finished is + * reported. Otherwise, the engine will report shown immediately right after redraw phase + * in {@link #updateSurface(boolean, boolean, boolean)}. + * + * @hide + */ + public boolean shouldWaitForEngineShown() { + return false; + } + + /** + * Reports the rendering is finished, stops waiting, then invokes + * {@link IWallpaperEngineWrapper#reportShown()}. + * + * @hide + */ + public void reportEngineShown(boolean waitForEngineShown) { + if (mIWallpaperEngine.mShownReported) return; + Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN); + if (!waitForEngineShown) { + mCaller.removeMessages(MSG_REPORT_SHOWN); + mCaller.sendMessage(message); + } else { + mCaller.sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(1)); + } + } + + /** * Control whether this wallpaper will receive raw touch events * from the window manager as the user interacts with the window * that is currently displaying the wallpaper. By default they @@ -930,7 +961,7 @@ public abstract class WallpaperService extends Service { void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) { if (mDestroyed) { - Log.w(TAG, "Ignoring updateSurface: destroyed"); + Log.w(TAG, "Ignoring updateSurface due to destroyed"); } boolean fixedSize = false; @@ -1197,7 +1228,6 @@ public abstract class WallpaperService extends Service { + this); onVisibilityChanged(false); } - } finally { mIsCreating = false; mSurfaceCreated = true; @@ -1207,7 +1237,7 @@ public abstract class WallpaperService extends Service { processLocalColors(mPendingXOffset, mPendingXOffsetStep); } reposition(); - mIWallpaperEngine.reportShown(); + reportEngineShown(shouldWaitForEngineShown()); } } catch (RemoteException ex) { } @@ -2201,6 +2231,9 @@ public abstract class WallpaperService extends Service { // Connection went away, nothing to do in here. } } break; + case MSG_REPORT_SHOWN: { + reportShown(); + } break; default : Log.w(TAG, "Unknown message type " + message.what); } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 802163617b3b..a7ecf1f2a81d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -814,9 +814,10 @@ interface IWindowManager * @param displayId The display associated with the window context * @param options A bundle used to pass window-related options and choose the right DisplayArea * - * @return {@code true} if the WindowContext is attached to the DisplayArea successfully. + * @return the DisplayArea's {@link android.app.res.Configuration} if the WindowContext is + * attached to the DisplayArea successfully. {@code null}, otherwise. */ - boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, + Configuration attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, in Bundle options); /** diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl index 8b8dba89ea67..69bc1b5f7763 100644 --- a/core/java/android/window/ITaskOrganizer.aidl +++ b/core/java/android/window/ITaskOrganizer.aidl @@ -88,4 +88,9 @@ oneway interface ITaskOrganizer { * user has pressed back on the root activity of a task controlled by the task organizer. */ void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo); + + /** + * Called when the IME has drawn on the organized task. + */ + void onImeDrawnOnTask(int taskId); } diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index c7c91cdd0941..d8723a821a22 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -144,6 +144,10 @@ public class TaskOrganizer extends WindowOrganizer { @BinderThread public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} + /** @hide */ + @BinderThread + public void onImeDrawnOnTask(int taskId) {} + /** * Creates a persistent root task in WM for a particular windowing-mode. * @param displayId The display to create the root task on. @@ -287,6 +291,11 @@ public class TaskOrganizer extends WindowOrganizer { public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) { mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info)); } + + @Override + public void onImeDrawnOnTask(int taskId) { + mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId)); + } }; private ITaskOrganizerController getController() { diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 901625b0732c..6d0a6bd559ae 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -26,7 +26,6 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.res.Configuration; import android.os.Bundle; -import android.os.IBinder; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; @@ -67,7 +66,7 @@ public class WindowContext extends ContextWrapper { mType = type; mOptions = options; mWindowManager = createWindowContextWindowManager(this); - IBinder token = getWindowContextToken(); + WindowTokenClient token = (WindowTokenClient) getWindowContextToken(); mController = new WindowContextController(token); Reference.reachabilityFence(this); diff --git a/core/java/android/window/WindowContextController.java b/core/java/android/window/WindowContextController.java index d84f571931fd..505b45008663 100644 --- a/core/java/android/window/WindowContextController.java +++ b/core/java/android/window/WindowContextController.java @@ -19,6 +19,7 @@ package android.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; @@ -46,7 +47,7 @@ public class WindowContextController { @VisibleForTesting public boolean mAttachedToDisplayArea; @NonNull - private final IBinder mToken; + private final WindowTokenClient mToken; /** * Window Context Controller constructor @@ -54,14 +55,13 @@ public class WindowContextController { * @param token The token used to attach to a window manager node. It is usually from * {@link Context#getWindowContextToken()}. */ - public WindowContextController(@NonNull IBinder token) { - mToken = token; - mWms = WindowManagerGlobal.getWindowManagerService(); + public WindowContextController(@NonNull WindowTokenClient token) { + this(token, WindowManagerGlobal.getWindowManagerService()); } /** Used for test only. DO NOT USE it in production code. */ @VisibleForTesting - public WindowContextController(@NonNull IBinder token, IWindowManager mockWms) { + public WindowContextController(@NonNull WindowTokenClient token, IWindowManager mockWms) { mToken = token; mWms = mockWms; } @@ -81,8 +81,14 @@ public class WindowContextController { + "a DisplayArea once."); } try { - mAttachedToDisplayArea = mWms.attachWindowContextToDisplayArea(mToken, type, displayId, - options); + final Configuration configuration = mWms.attachWindowContextToDisplayArea(mToken, type, + displayId, options); + if (configuration != null) { + mAttachedToDisplayArea = true; + // Send the DisplayArea's configuration to WindowContext directly instead of + // waiting for dispatching from WMS. + mToken.onConfigurationChanged(configuration, displayId); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java index 6abf5575d353..4dcd2e74a53f 100644 --- a/core/java/android/window/WindowTokenClient.java +++ b/core/java/android/window/WindowTokenClient.java @@ -24,6 +24,8 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; +import com.android.internal.annotations.VisibleForTesting; + import java.lang.ref.WeakReference; /** @@ -33,7 +35,7 @@ import java.lang.ref.WeakReference; * {@link Context#getWindowContextToken() the token of non-Activity UI Contexts}. * * @see WindowContext - * @see android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, Bundle) + * @see android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, Bundle) * * @hide */ @@ -50,8 +52,8 @@ public class WindowTokenClient extends IWindowToken.Stub { * Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient} * can only attach one {@link Context}. * <p>This method must be called before invoking - * {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int, - * Bundle, boolean)}.<p/> + * {@link android.view.IWindowManager#attachWindowContextToDisplayArea(IBinder, int, int, + * Bundle)}.<p/> * * @param context context to be attached * @throws IllegalStateException if attached context has already existed. @@ -63,6 +65,13 @@ public class WindowTokenClient extends IWindowToken.Stub { mContextRef = new WeakReference<>(context); } + /** + * Called when {@link Configuration} updates from the server side receive. + * + * @param newConfig the updated {@link Configuration} + * @param newDisplayId the updated {@link android.view.Display} ID + */ + @VisibleForTesting @Override public void onConfigurationChanged(Configuration newConfig, int newDisplayId) { final Context context = mContextRef.get(); diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java index ce75f45d0897..068b882eb4f7 100644 --- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java +++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java @@ -165,7 +165,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo { // Now fetch app icon and raster with no badging even in work profile Bitmap appIcon = mSelectableTargetInfoCommunicator.makePresentationGetter(info) - .getIconBitmap(android.os.Process.myUserHandle()); + .getIconBitmap(mContext.getUser()); // Raster target drawable with appIcon as a badge SimpleIconFactory sif = SimpleIconFactory.obtain(mContext); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 7e286f042384..a817119a735f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -8618,7 +8618,7 @@ public class BatteryStatsImpl extends BatteryStats { * inactive so can be dropped. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public boolean reset(long uptimeUs, long realtimeUs) { + public boolean reset(long uptimeUs, long realtimeUs, int resetReason) { boolean active = false; mOnBatteryBackgroundTimeBase.init(uptimeUs, realtimeUs); @@ -8688,7 +8688,11 @@ public class BatteryStatsImpl extends BatteryStats { resetIfNotNull(mBluetoothControllerActivity, false, realtimeUs); resetIfNotNull(mModemControllerActivity, false, realtimeUs); - MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats); + if (resetReason == RESET_REASON_MEASURED_ENERGY_BUCKETS_CHANGE) { + mUidMeasuredEnergyStats = null; + } else { + MeasuredEnergyStats.resetIfNotNull(mUidMeasuredEnergyStats); + } resetIfNotNull(mUserCpuTime, false, realtimeUs); resetIfNotNull(mSystemCpuTime, false, realtimeUs); @@ -11371,7 +11375,7 @@ public class BatteryStatsImpl extends BatteryStats { mNumConnectivityChange = 0; for (int i=0; i<mUidStats.size(); i++) { - if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs)) { + if (mUidStats.valueAt(i).reset(uptimeUs, elapsedRealtimeUs, resetReason)) { mUidStats.valueAt(i).detachFromTimeBase(); mUidStats.remove(mUidStats.keyAt(i)); i--; diff --git a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java index 9b51a8ef6410..bb307a0d29d8 100644 --- a/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java +++ b/core/java/com/android/internal/os/CustomMeasuredPowerCalculator.java @@ -21,13 +21,18 @@ import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.UidBatteryConsumer; +import android.util.Slog; import android.util.SparseArray; +import java.util.Arrays; + /** * Calculates the amount of power consumed by custom energy consumers (i.e. consumers of type * {@link android.hardware.power.stats.EnergyConsumerType#OTHER}). */ public class CustomMeasuredPowerCalculator extends PowerCalculator { + private static final String TAG = "CustomMeasuredPowerCalc"; + public CustomMeasuredPowerCalculator(PowerProfile powerProfile) { } @@ -76,9 +81,9 @@ public class CustomMeasuredPowerCalculator extends PowerCalculator { if (totalPowerMah == null) { newTotalPowerMah = new double[customMeasuredPowerMah.length]; } else if (totalPowerMah.length != customMeasuredPowerMah.length) { - newTotalPowerMah = new double[customMeasuredPowerMah.length]; - System.arraycopy(totalPowerMah, 0, newTotalPowerMah, 0, - customMeasuredPowerMah.length); + Slog.wtf(TAG, "Number of custom energy components is not the same for all apps: " + + totalPowerMah.length + ", " + customMeasuredPowerMah.length); + newTotalPowerMah = Arrays.copyOf(totalPowerMah, customMeasuredPowerMah.length); } else { newTotalPowerMah = totalPowerMah; } diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java index b321ac08912b..a09c8236b47d 100644 --- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java +++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java @@ -124,7 +124,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { - sendCloseSystemWindows(); mContext.startActivity(intent); } catch (ActivityNotFoundException e) { startCallActivity(); @@ -147,7 +146,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { dispatcher.performedLongPress(event); if (isUserSetupComplete()) { mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); // Broadcast an intent that the Camera button was longpressed Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); @@ -178,7 +176,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - sendCloseSystemWindows(); getSearchManager().stopSearch(); mContext.startActivity(intent); // Only clear this if we successfully start the @@ -272,7 +269,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { @UnsupportedAppUsage void startCallActivity() { - sendCloseSystemWindows(); Intent intent = new Intent(Intent.ACTION_CALL_BUTTON); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { @@ -319,10 +315,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { return mMediaSessionManager; } - void sendCloseSystemWindows() { - PhoneWindow.sendCloseSystemWindows(mContext, null); - } - private void handleVolumeKeyEvent(KeyEvent keyEvent) { getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(keyEvent, AudioManager.USE_DEFAULT_STREAM_TYPE); diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 498505cd46ff..cd1bbb6bc6fe 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -17,6 +17,7 @@ package com.android.internal.widget; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_MANAGED; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; @@ -1272,6 +1273,14 @@ public class LockPatternUtils { } /** + * Whether the user is not allowed to set any credentials via PASSWORD_QUALITY_MANAGED. + */ + public boolean isCredentialsDisabledForUser(int userId) { + return getDevicePolicyManager().getPasswordQuality(/* admin= */ null, userId) + == PASSWORD_QUALITY_MANAGED; + } + + /** * @see StrongAuthTracker#isTrustAllowedForUser */ public boolean isTrustAllowedForUser(int userId) { diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java index a5a98a98f0be..109b7ab73d6f 100644 --- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java +++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java @@ -17,6 +17,8 @@ package android.service.notification; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertNull; import static org.junit.Assert.assertFalse; @@ -51,6 +53,7 @@ public class StatusBarNotificationTest { private final Context mMockContext = mock(Context.class); @Mock + private Context mRealContext; private PackageManager mPm; private static final String PKG = "com.example.o"; @@ -75,6 +78,8 @@ public class StatusBarNotificationTest { InstrumentationRegistry.getContext().getResources()); when(mMockContext.getPackageManager()).thenReturn(mPm); when(mMockContext.getApplicationInfo()).thenReturn(new ApplicationInfo()); + + mRealContext = InstrumentationRegistry.getContext(); } @Test @@ -199,6 +204,19 @@ public class StatusBarNotificationTest { } + @Test + public void testGetPackageContext_worksWithUserAll() { + String pkg = "com.android.systemui"; + int uid = 1000; + Notification notification = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID).build(); + StatusBarNotification sbn = new StatusBarNotification( + pkg, pkg, ID, TAG, uid, uid, notification, UserHandle.ALL, null, UID); + Context resultContext = sbn.getPackageContext(mRealContext); + assertNotNull(resultContext); + assertNotSame(mRealContext, resultContext); + assertEquals(pkg, resultContext.getPackageName()); + } + private StatusBarNotification getNotification(String pkg, String group, String channelId) { return getNotification(pkg, getNotificationBuilder(group, channelId)); } diff --git a/core/tests/coretests/src/android/window/WindowContextControllerTest.java b/core/tests/coretests/src/android/window/WindowContextControllerTest.java index 020f4a06b892..073e46827bbb 100644 --- a/core/tests/coretests/src/android/window/WindowContextControllerTest.java +++ b/core/tests/coretests/src/android/window/WindowContextControllerTest.java @@ -23,11 +23,13 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import android.content.res.Configuration; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.IWindowManager; @@ -38,6 +40,8 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; /** * Tests for {@link WindowContextController} @@ -53,15 +57,18 @@ import org.junit.runner.RunWith; @Presubmit public class WindowContextControllerTest { private WindowContextController mController; + @Mock private IWindowManager mMockWms; + @Mock + private WindowTokenClient mMockToken; @Before public void setUp() throws Exception { - mMockWms = mock(IWindowManager.class); - mController = new WindowContextController(new Binder(), mMockWms); - - doReturn(true).when(mMockWms).attachWindowContextToDisplayArea(any(), anyInt(), - anyInt(), any()); + MockitoAnnotations.initMocks(this); + mController = new WindowContextController(mMockToken, mMockWms); + doNothing().when(mMockToken).onConfigurationChanged(any(), anyInt()); + doReturn(new Configuration()).when(mMockWms).attachWindowContextToDisplayArea(any(), + anyInt(), anyInt(), any()); } @Test(expected = IllegalStateException.class) @@ -85,6 +92,7 @@ public class WindowContextControllerTest { null /* options */); assertThat(mController.mAttachedToDisplayArea).isTrue(); + verify(mMockToken).onConfigurationChanged(any(), eq(DEFAULT_DISPLAY)); mController.detachIfNeeded(); diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java index b851f0ad3414..0135fe84909a 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSensorTest.java @@ -403,7 +403,7 @@ public class BatteryStatsSensorTest extends TestCase { assertNotNull(sensor.getSensorBackgroundTime()); // Reset the stats. Since the sensor is still running, we should still see the timer - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); sensor = uid.getSensorStats().get(SENSOR_ID); assertNotNull(sensor); @@ -413,7 +413,7 @@ public class BatteryStatsSensorTest extends TestCase { bi.noteStopSensorLocked(UID, SENSOR_ID); // Now the sensor timer has stopped so this reset should also take out the sensor. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); sensor = uid.getSensorStats().get(SENSOR_ID); assertNull(sensor); @@ -465,7 +465,7 @@ public class BatteryStatsSensorTest extends TestCase { // Reset the stats. Since the sensor is still running, we should still see the timer // but still with 0 times. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which)); assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime)); assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which)); @@ -504,7 +504,7 @@ public class BatteryStatsSensorTest extends TestCase { // Reset the stats. Since the sensor is still running, we should still see the timer // but with 0 times. - bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000); + bi.getUidStatsLocked(UID).reset(clocks.uptime * 1000, clocks.realtime * 1000, 0); assertEquals(0, timer.getTotalTimeLocked(1000*clocks.realtime, which)); assertEquals(0, timer.getTotalDurationMsLocked(clocks.realtime)); assertEquals(0, bgTimer.getTotalTimeLocked(1000*clocks.realtime, which)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java index ba0ab6db1003..656bdff0c782 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -336,6 +336,13 @@ public class ShellTaskOrganizer extends TaskOrganizer implements } @Override + public void onImeDrawnOnTask(int taskId) { + if (mStartingWindow != null) { + mStartingWindow.onImeDrawnOnTask(taskId); + } + } + + @Override public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { synchronized (mLock) { onTaskAppeared(new TaskAppearedInfo(taskInfo, leash)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 954ca14b4960..e511bffad247 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -445,6 +445,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController> mOneHandedSettingsUtil.registerSettingsKeyObserver( Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, mContext.getContentResolver(), mShortcutEnabledObserver, newUserId); + mOneHandedSettingsUtil.registerSettingsKeyObserver( + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, + mContext.getContentResolver(), mShortcutEnabledObserver, newUserId); } private void unregisterSettingObservers() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 7cf4fb7a811d..ff333c8c659d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -171,9 +171,22 @@ public final class OneHandedSettingsUtil { * @return true if user enabled one-handed shortcut in settings, false otherwise. */ public boolean getShortcutEnabled(ContentResolver resolver, int userId) { - final String targets = Settings.Secure.getStringForUser(resolver, + // Checks SOFTWARE_SHORTCUT_KEY + final String targetsSwKey = Settings.Secure.getStringForUser(resolver, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, userId); - return TextUtils.isEmpty(targets) ? false : targets.contains(ONE_HANDED_MODE_TARGET_NAME); + if (!TextUtils.isEmpty(targetsSwKey) && targetsSwKey.contains( + ONE_HANDED_MODE_TARGET_NAME)) { + return true; + } + + // Checks HARDWARE_SHORTCUT_KEY + final String targetsHwKey = Settings.Secure.getStringForUser(resolver, + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userId); + if (!TextUtils.isEmpty(targetsHwKey) && targetsHwKey.contains( + ONE_HANDED_MODE_TARGET_NAME)) { + return true; + } + return false; } /** 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 fc7c86d669cb..147f5e30f9d6 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 @@ -545,6 +545,15 @@ public class StartingSurfaceDrawer { removeWindowSynced(taskId, null, null, false); } + void onImeDrawnOnTask(int taskId) { + final StartingWindowRecord record = mStartingWindowRecords.get(taskId); + if (record != null && record.mTaskSnapshotWindow != null + && record.mTaskSnapshotWindow.hasImeSurface()) { + record.mTaskSnapshotWindow.removeImmediately(); + } + mStartingWindowRecords.remove(taskId); + } + protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame, boolean playRevealAnimation) { final StartingWindowRecord record = mStartingWindowRecords.get(taskId); @@ -572,14 +581,15 @@ public class StartingSurfaceDrawer { Slog.e(TAG, "Found empty splash screen, remove!"); removeWindowInner(record.mDecorView, false); } + mStartingWindowRecords.remove(taskId); } if (record.mTaskSnapshotWindow != null) { if (DEBUG_TASK_SNAPSHOT) { Slog.v(TAG, "Removing task snapshot window for " + taskId); } - record.mTaskSnapshotWindow.remove(); + record.mTaskSnapshotWindow.scheduleRemove( + () -> mStartingWindowRecords.remove(taskId)); } - mStartingWindowRecords.remove(taskId); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java index e84d498a9258..dee21b093dce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java @@ -177,6 +177,13 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo } /** + * Called when the IME has drawn on the organized task. + */ + public void onImeDrawnOnTask(int taskId) { + mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.onImeDrawnOnTask(taskId)); + } + + /** * Called when the content of a task is ready to show, starting window can be removed. */ public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java index 6052d3dee891..72295148f678 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java @@ -16,7 +16,6 @@ package com.android.wm.shell.startingsurface; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.graphics.Color.WHITE; import static android.graphics.Color.alpha; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; @@ -64,7 +63,6 @@ import android.graphics.RectF; import android.hardware.HardwareBuffer; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.os.Trace; import android.util.MergedConfiguration; import android.util.Slog; @@ -119,7 +117,12 @@ public class TaskSnapshotWindow { private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s"; private static final long DELAY_REMOVAL_TIME_GENERAL = 100; - private static final long DELAY_REMOVAL_TIME_IME_VISIBLE = 350; + /** + * The max delay time in milliseconds for removing the task snapshot window with IME visible. + * Ideally the delay time will be shorter when receiving + * {@link StartingSurfaceDrawer#onImeDrawnOnTask(int)}. + */ + private static final long MAX_DELAY_REMOVAL_TIME_IME_VISIBLE = 450; //tmp vars for unused relayout params private static final Point TMP_SURFACE_SIZE = new Point(); @@ -138,7 +141,6 @@ public class TaskSnapshotWindow { private final RectF mTmpDstFrame = new RectF(); private final CharSequence mTitle; private boolean mHasDrawn; - private long mShownTime; private boolean mSizeMismatch; private final Paint mBackgroundPaint = new Paint(); private final int mActivityType; @@ -148,6 +150,8 @@ public class TaskSnapshotWindow { private final SurfaceControl.Transaction mTransaction; private final Matrix mSnapshotMatrix = new Matrix(); private final float[] mTmpFloat9 = new float[9]; + private Runnable mScheduledRunnable; + private final boolean mHasImeSurface; static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken, TaskSnapshot snapshot, ShellExecutor splashScreenExecutor, @@ -216,7 +220,7 @@ public class TaskSnapshotWindow { taskDescription.setBackgroundColor(WHITE); } - final long delayRemovalTime = snapshot.hasImeSurface() ? DELAY_REMOVAL_TIME_IME_VISIBLE + final long delayRemovalTime = snapshot.hasImeSurface() ? MAX_DELAY_REMOVAL_TIME_IME_VISIBLE : DELAY_REMOVAL_TIME_GENERAL; final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow( @@ -281,12 +285,17 @@ public class TaskSnapshotWindow { mDelayRemovalTime = delayRemovalTime; mTransaction = new SurfaceControl.Transaction(); mClearWindowHandler = clearWindowHandler; + mHasImeSurface = snapshot.hasImeSurface(); } int getBackgroundColor() { return mBackgroundPaint.getColor(); } + boolean hasImeSurface() { + return mHasImeSurface; + } + /** * Ask system bar background painter to draw status bar background. * @hide @@ -304,21 +313,26 @@ public class TaskSnapshotWindow { mSystemBarBackgroundPainter.drawNavigationBarBackground(c); } - void remove() { - final long now = SystemClock.uptimeMillis(); - if ((now - mShownTime < mDelayRemovalTime) - // Show the latest content as soon as possible for unlocking to home. - && mActivityType != ACTIVITY_TYPE_HOME) { - final long delayTime = mShownTime + mDelayRemovalTime - now; - mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime); - if (DEBUG) { - Slog.d(TAG, "Defer removing snapshot surface in " + delayTime); - } - return; + void scheduleRemove(Runnable onRemove) { + if (mScheduledRunnable != null) { + mSplashScreenExecutor.removeCallbacks(mScheduledRunnable); + mScheduledRunnable = null; + } + mScheduledRunnable = () -> { + TaskSnapshotWindow.this.removeImmediately(); + onRemove.run(); + }; + mSplashScreenExecutor.executeDelayed(mScheduledRunnable, mDelayRemovalTime); + if (DEBUG) { + Slog.d(TAG, "Defer removing snapshot surface in " + mDelayRemovalTime); } + } + + void removeImmediately() { + mSplashScreenExecutor.removeCallbacks(mScheduledRunnable); try { if (DEBUG) { - Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn); + Slog.d(TAG, "Removing taskSnapshot surface, mHasDrawn: " + mHasDrawn); } mSession.remove(mWindow); } catch (RemoteException e) { @@ -356,7 +370,6 @@ public class TaskSnapshotWindow { } else { drawSizeMatchSnapshot(); } - mShownTime = SystemClock.uptimeMillis(); mHasDrawn = true; reportDrawn(); 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 d536adb9f8ae..eef0d9bb268f 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 @@ -15,38 +15,53 @@ */ package com.android.wm.shell.startingsurface; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertEquals; 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.verify; +import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.ColorSpace; +import android.graphics.Point; import android.graphics.Rect; +import android.hardware.HardwareBuffer; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.UserHandle; import android.testing.TestableContext; +import android.view.IWindowSession; +import android.view.InsetsState; +import android.view.Surface; import android.view.SurfaceControl; import android.view.View; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.WindowMetrics; import android.window.StartingWindowInfo; +import android.window.TaskSnapshot; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -61,6 +76,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; import java.util.function.IntSupplier; @@ -78,6 +94,7 @@ public class StartingSurfaceDrawerTests { private TransactionPool mTransactionPool; private final Handler mTestHandler = new Handler(Looper.getMainLooper()); + private ShellExecutor mTestExecutor; private final TestableContext mTestContext = new TestContext( InstrumentationRegistry.getInstrumentation().getTargetContext()); TestStartingSurfaceDrawer mStartingSurfaceDrawer; @@ -138,9 +155,9 @@ public class StartingSurfaceDrawerTests { doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics(); doNothing().when(mMockWindowManager).addView(any(), any()); - - mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(mTestContext, - new HandlerExecutor(mTestHandler), mTransactionPool)); + mTestExecutor = new HandlerExecutor(mTestHandler); + mStartingSurfaceDrawer = spy( + new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mTransactionPool)); } @Test @@ -205,6 +222,48 @@ public class StartingSurfaceDrawerTests { assertEquals(0, windowColor3.mReuseCount); } + @Test + public void testRemoveTaskSnapshotWithImeSurfaceWhenOnImeDrawn() throws Exception { + final int taskId = 1; + final StartingWindowInfo windowInfo = + createWindowInfo(taskId, android.R.style.Theme); + TaskSnapshot snapshot = createTaskSnapshot(100, 100, new Point(100, 100), + new Rect(0, 0, 0, 50), true /* hasImeSurface */); + final IWindowSession session = WindowManagerGlobal.getWindowSession(); + spyOn(session); + doReturn(WindowManagerGlobal.ADD_OKAY).when(session).addToDisplay( + any() /* window */, any() /* attrs */, + anyInt() /* viewVisibility */, anyInt() /* displayId */, + any() /* requestedVisibility */, any() /* outInputChannel */, + any() /* outInsetsState */, any() /* outActiveControls */); + TaskSnapshotWindow mockSnapshotWindow = TaskSnapshotWindow.create(windowInfo, + mBinder, + snapshot, mTestExecutor, () -> { + }); + spyOn(mockSnapshotWindow); + try (AutoCloseable mockTaskSnapshotSession = new AutoCloseable() { + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(TaskSnapshotWindow.class) + .startMocking(); + @Override + public void close() { + mockSession.finishMocking(); + } + }) { + when(TaskSnapshotWindow.create(eq(windowInfo), eq(mBinder), eq(snapshot), any(), + any())).thenReturn(mockSnapshotWindow); + // Simulate a task snapshot window created with IME snapshot shown. + mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, mBinder, snapshot); + waitHandlerIdle(mTestHandler); + + // Verify the task snapshot with IME snapshot will be removed when received the real IME + // drawn callback. + mStartingSurfaceDrawer.onImeDrawnOnTask(1); + verify(mockSnapshotWindow).removeImmediately(); + } + } + private StartingWindowInfo createWindowInfo(int taskId, int themeResId) { StartingWindowInfo windowInfo = new StartingWindowInfo(); final ActivityInfo info = new ActivityInfo(); @@ -216,10 +275,27 @@ public class StartingSurfaceDrawerTests { taskInfo.taskId = taskId; windowInfo.targetActivityInfo = info; windowInfo.taskInfo = taskInfo; + windowInfo.topOpaqueWindowInsetsState = new InsetsState(); + windowInfo.mainWindowLayoutParams = new WindowManager.LayoutParams(); + windowInfo.topOpaqueWindowLayoutParams = new WindowManager.LayoutParams(); return windowInfo; } private static void waitHandlerIdle(Handler handler) { handler.runWithScissors(() -> { }, 0 /* timeout */); } + + private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize, + Rect contentInsets, boolean hasImeSurface) { + final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888, + 1, HardwareBuffer.USAGE_CPU_READ_RARELY); + return new TaskSnapshot( + System.currentTimeMillis(), + new ComponentName("", ""), buffer, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + Surface.ROTATION_0, taskSize, contentInsets, false, + true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, + 0 /* systemUiVisibility */, false /* isTranslucent */, + hasImeSurface /* hasImeSurface */); + } } diff --git a/packages/SettingsLib/res/values-as/arrays.xml b/packages/SettingsLib/res/values-as/arrays.xml index 50bfbe07b205..89739f6f6fc4 100644 --- a/packages/SettingsLib/res/values-as/arrays.xml +++ b/packages/SettingsLib/res/values-as/arrays.xml @@ -228,7 +228,7 @@ <item msgid="8612549335720461635">"৪কে. (সুৰক্ষিত)"</item> <item msgid="7322156123728520872">"৪কে. (বৰ্ধিত)"</item> <item msgid="7735692090314849188">"৪কে. (বৰ্ধিত, সুৰক্ষিত)"</item> - <item msgid="7346816300608639624">"৭২০পি., ১০৮০পি. (দ্বৈত স্ক্ৰীণ)"</item> + <item msgid="7346816300608639624">"৭২০পি., ১০৮০পি. (দ্বৈত স্ক্ৰীন)"</item> </string-array> <string-array name="enable_opengl_traces_entries"> <item msgid="4433736508877934305">"নাই"</item> @@ -243,7 +243,7 @@ </string-array> <string-array name="track_frame_time_entries"> <item msgid="634406443901014984">"অফ হৈ আছে"</item> - <item msgid="1288760936356000927">"স্ক্ৰীণত দণ্ড হিচাপে"</item> + <item msgid="1288760936356000927">"স্ক্ৰীনত দণ্ড হিচাপে"</item> <item msgid="5023908510820531131">"<xliff:g id="AS_TYPED_COMMAND">adb shell dumpsys gfxinfo</xliff:g>ত"</item> </string-array> <string-array name="debug_hw_overdraw_entries"> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index 1ae3452ac847..9f9b11d1e3b1 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -238,7 +238,7 @@ <string name="bugreport_in_power" msgid="8664089072534638709">"বাগ ৰিপৰ্টৰ শ্ৱৰ্টকাট"</string> <string name="bugreport_in_power_summary" msgid="1885529649381831775">"পাৱাৰ মেনুত বাগ প্ৰতিবেদন গ্ৰহণ কৰিবলৈ এটা বুটাম দেখুৱাওক"</string> <string name="keep_screen_on" msgid="1187161672348797558">"জাগ্ৰত কৰি ৰাখক"</string> - <string name="keep_screen_on_summary" msgid="1510731514101925829">"চ্চাৰ্জ হৈ থকাৰ সময়ত স্ক্ৰীণ কেতিয়াও সুপ্ত অৱস্থালৈ নাযায়"</string> + <string name="keep_screen_on_summary" msgid="1510731514101925829">"চ্চাৰ্জ হৈ থকাৰ সময়ত স্ক্ৰীন কেতিয়াও সুপ্ত অৱস্থালৈ নাযায়"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"ব্লুটুথ HCI স্নুপ ল’গ সক্ষম কৰক"</string> <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"ব্লুটুথ পেকেট সংগ্ৰহ কৰক। (এই ছেটিংটো সলনি কৰাৰ পিছত ব্লুটুথ ট’গল কৰক)"</string> <string name="oem_unlock_enable" msgid="5334869171871566731">"ঔইএম আনলক"</string> @@ -331,9 +331,9 @@ <string name="media_category" msgid="8122076702526144053">"মিডিয়া"</string> <string name="debug_monitoring_category" msgid="1597387133765424994">"নিৰীক্ষণ কৰি থকা হৈছে"</string> <string name="strict_mode" msgid="889864762140862437">"কঠোৰ ম’ড সক্ষম কৰা হৈছে"</string> - <string name="strict_mode_summary" msgid="1838248687233554654">"যেতিয়া এপসমূহে মুখ্য থ্ৰেডত দীঘলীয়া কাৰ্যকলাপ চলাই, তেতিয়া স্ক্ৰীণ ফ্লাশ্ব কৰক"</string> + <string name="strict_mode_summary" msgid="1838248687233554654">"যেতিয়া এপ্সমূহে মুখ্য থ্ৰেডত দীঘলীয়া কাৰ্যকলাপ চলাই, তেতিয়া স্ক্ৰীন ফ্লাশ্ব কৰক"</string> <string name="pointer_location" msgid="7516929526199520173">"পইণ্টাৰৰ অৱস্থান"</string> - <string name="pointer_location_summary" msgid="957120116989798464">"চলিত স্পৰ্শ-বিষয়ক তথ্যসহ স্ক্ৰীণ অভাৰলে\'"</string> + <string name="pointer_location_summary" msgid="957120116989798464">"চলিত স্পৰ্শ-বিষয়ক তথ্যসহ স্ক্ৰীন অভাৰলে’"</string> <string name="show_touches" msgid="8437666942161289025">"টেপসমূহ দেখুৱাওক"</string> <string name="show_touches_summary" msgid="3692861665994502193">"টিপিলে দৃশ্যায়িত ফীডবেক দিয়ক"</string> <string name="show_screen_updates" msgid="2078782895825535494">"পৃষ্ঠভাগৰ আপডেইট দেখুৱাওক"</string> @@ -344,7 +344,7 @@ <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"হাৰ্ডৱেৰ লেয়াৰ আপডেইট হওতে সিঁহতক সেউজীয়া ৰঙেৰে ফ্লাশ্ব কৰক"</string> <string name="debug_hw_overdraw" msgid="8944851091008756796">"GPU অভাৰড্ৰ ডিবাগ কৰক"</string> <string name="disable_overlays" msgid="4206590799671557143">"HW অ’ভাৰলে অক্ষম কৰক"</string> - <string name="disable_overlays_summary" msgid="1954852414363338166">"স্ক্ৰীণ কম্প’জিট কৰাৰ বাবে সদায় জিপিইউ ব্যৱহাৰ কৰক"</string> + <string name="disable_overlays_summary" msgid="1954852414363338166">"স্ক্ৰীন কম্প’জিট কৰাৰ বাবে সদায় জিপিইউ ব্যৱহাৰ কৰক"</string> <string name="simulate_color_space" msgid="1206503300335835151">"ৰঙৰ ঠাই ছিমিউলেইট কৰক"</string> <string name="enable_opengl_traces_title" msgid="4638773318659125196">"OpenGL ট্ৰেছ সক্ষম কৰক"</string> <string name="usb_audio_disable_routing" msgid="3367656923544254975">"ইউএছবি অডিঅ\' ৰাউটিং অক্ষম কৰক"</string> @@ -352,7 +352,7 @@ <string name="debug_layout" msgid="1659216803043339741">"লেআউটৰ সময় দেখুৱাওক"</string> <string name="debug_layout_summary" msgid="8825829038287321978">"ক্লিপ বাউণ্ড, মাৰ্জিন আদিসমূহ দেখুৱাওক"</string> <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"আৰটিএল চানেকিৰ দিশ বলেৰে সলনি কৰক"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"সকলো ভাষাৰ বাবে স্ক্ৰীণৰ চানেকিৰ দিশ RTLলৈ বলেৰে সলনি কৰক"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"সকলো ভাষাৰ বাবে স্ক্ৰীনৰ চানেকিৰ দিশ RTLলৈ বলেৰে সলনি কৰক"</string> <string name="window_blurs" msgid="6831008984828425106">"ৱিণ্ড’ স্তৰত অস্পষ্ট কৰাৰ অনুমতি দিয়ক"</string> <string name="force_msaa" msgid="4081288296137775550">"বল ৪গুণ MSAA"</string> <string name="force_msaa_summary" msgid="9070437493586769500">"OpenGL ES 2.0 এপত ৪গুণ MSAA সক্ষম কৰক"</string> @@ -373,7 +373,7 @@ <string name="show_all_anrs" msgid="9160563836616468726">"নেপথ্য এএনআৰবোৰ দেখুৱাওক"</string> <string name="show_all_anrs_summary" msgid="8562788834431971392">"নেপথ্য এপসমূহৰ বাবে এপে সঁহাৰি দিয়া নাই ডায়ল\'গ প্ৰদৰ্শন কৰক"</string> <string name="show_notification_channel_warnings" msgid="3448282400127597331">"জাননী চ্চেনেলৰ সকীয়নিসমূহ দেখুৱাওক"</string> - <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীণত সকীয়নি প্ৰদৰ্শন হয়"</string> + <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"কোনো এপে বৈধ চ্চেনেল নোহোৱাকৈ কোনো জাননী প\'ষ্ট কৰিলে স্ক্ৰীনত সকীয়নি প্ৰদৰ্শন হয়"</string> <string name="force_allow_on_external" msgid="9187902444231637880">"বাহ্যিক সঞ্চয়াগাৰত এপক বলেৰে অনুমতি দিয়ক"</string> <string name="force_allow_on_external_summary" msgid="8525425782530728238">"মেনিফেষ্টৰ মান যিয়েই নহওক, বাহ্যিক সঞ্চয়াগাৰত লিখিবলৈ যিকোনো এপক উপযুক্ত কৰি তোলে"</string> <string name="force_resizable_activities" msgid="7143612144399959606">"বলেৰে কাৰ্যকলাপসমূহৰ আকাৰ সলনি কৰিব পৰা কৰক"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 921caba34e13..108d86d185e0 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -286,7 +286,7 @@ <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string> <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Quand ce mode est activé, l\'adresse MAC de cet appareil peut changer chaque fois qu\'il se connecte à un réseau Wi-Fi où le changement aléatoire d\'adresse MAC est activé"</string> <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string> - <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string> + <string name="wifi_unmetered_label" msgid="6174142840934095093">"Sans compteur"</string> <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string> <string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Tailles enreg. par tampon journal"</string> <string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Effacer l\'espace de stockage persistant de l\'enregistreur ?"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index cbf92af607d2..0f381c966932 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -542,7 +542,7 @@ <string name="delete_blob_text" msgid="2819192607255625697">"Ортақ деректерді жою"</string> <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Осы ортақ деректерді шынымен жойғыңыз келе ме?"</string> <string name="user_add_user_item_summary" msgid="5748424612724703400">"Пайдаланушылардың өздерінің қолданбалары мен мазмұны болады"</string> - <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Өз есептік жазбаңыздан қолданбалар мен мазмұнға қол жетімділікті шектеуіңізге болады"</string> + <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Өз аккаунтыңыздан қолданбалар мен мазмұнға қол жетімділікті шектеуіңізге болады"</string> <string name="user_add_user_item_title" msgid="2394272381086965029">"Пайдаланушы"</string> <string name="user_add_profile_item_title" msgid="3111051717414643029">"Шектелген профайл"</string> <string name="user_add_user_title" msgid="5457079143694924885">"Жаңа пайдаланушы қосылсын ба?"</string> diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml index 801c037684f9..195fc47e8c64 100644 --- a/packages/SettingsLib/res/values-ko/arrays.xml +++ b/packages/SettingsLib/res/values-ko/arrays.xml @@ -28,7 +28,7 @@ <item msgid="2837871868181677206">"IP 주소를 가져오는 중..."</item> <item msgid="4613015005934755724">"연결됨"</item> <item msgid="3763530049995655072">"일시 정지됨"</item> - <item msgid="7852381437933824454">"연결을 끊는 중…"</item> + <item msgid="7852381437933824454">"연결 해제 중…"</item> <item msgid="5046795712175415059">"연결 끊김"</item> <item msgid="2473654476624070462">"실패"</item> <item msgid="9146847076036105115">"차단됨"</item> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 97ad0a0ef347..c455c14b1226 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -65,7 +65,7 @@ <string name="wifi_passpoint_expired" msgid="6540867261754427561">"만료됨"</string> <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string> <string name="bluetooth_disconnected" msgid="7739366554710388701">"연결 끊김"</string> - <string name="bluetooth_disconnecting" msgid="7638892134401574338">"연결을 끊는 중…"</string> + <string name="bluetooth_disconnecting" msgid="7638892134401574338">"연결 해제 중…"</string> <string name="bluetooth_connecting" msgid="5871702668260192755">"연결 중…"</string> <string name="bluetooth_connected" msgid="8065345572198502293">"연결됨<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string> <string name="bluetooth_pairing" msgid="4269046942588193600">"페어링 중..."</string> diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 72b027af1bf6..098b7e8dedbe 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -142,4 +142,8 @@ <item name="android:shadowColor">@color/keyguard_shadow_color</item> <item name="android:shadowRadius">?attr/shadowRadius</item> </style> + + <style name="TextAppearance.Keyguard.BottomArea.Button"> + <item name="android:shadowRadius">0</item> + </style> </resources> diff --git a/packages/SystemUI/res/drawable/logout_button_background.xml b/packages/SystemUI/res/drawable/logout_button_background.xml index eafd663f19d9..34434be7aefb 100644 --- a/packages/SystemUI/res/drawable/logout_button_background.xml +++ b/packages/SystemUI/res/drawable/logout_button_background.xml @@ -17,7 +17,8 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:shape="rectangle"> - <solid android:color="@color/logout_button_bg_color"/> + <solid android:color="?androidprv:attr/colorAccentPrimary"/> <corners android:radius="@dimen/logout_button_corner_radius"/> </shape> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index b841419c1c75..d286832631ba 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -39,7 +39,7 @@ android:layout_width="wrap_content" android:layout_height="32dp" android:textColor="?android:attr/textColorPrimary" - android:fontFamily="google-sans" + android:fontFamily="@*android:string/config_headlineFontFamily" android:textSize="24sp"/> <TextView @@ -50,7 +50,7 @@ android:layout_marginTop="4dp" android:ellipsize="end" android:maxLines="1" - android:fontFamily="google-sans" + android:fontFamily="@*android:string/config_headlineFontFamily" android:textSize="14sp"/> </LinearLayout> @@ -87,24 +87,49 @@ android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout - android:id="@+id/internet_list" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout + android:id="@+id/ethernet_layout" + style="@style/InternetDialog.Network" + android:background="@drawable/settingslib_switch_bar_bg_on" + android:visibility="gone"> + + <FrameLayout + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center_vertical|start" + android:clickable="false"> + <ImageView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:autoMirrored="true" + android:src="@drawable/stat_sys_ethernet_fully" + android:tint="@color/connected_network_primary_color"/> + </FrameLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="start|center_vertical" + android:orientation="vertical" + android:clickable="false"> + <TextView + android:text="@string/ethernet_label" + style="@style/InternetDialog.NetworkTitle.Active"/> + <TextView + android:text="@string/to_switch_networks_disconnect_ethernet" + style="@style/InternetDialog.NetworkSummary.Active"/> + </LinearLayout> + </LinearLayout> + + <LinearLayout android:id="@+id/mobile_network_layout" - android:layout_width="match_parent" - android:layout_height="88dp" - android:clickable="true" - android:focusable="true" - android:background="?android:attr/selectableItemBackground" - android:layout_gravity="center_vertical|start" - android:orientation="horizontal" - android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:paddingStart="22dp" - android:paddingEnd="22dp"> + style="@style/InternetDialog.Network"> <FrameLayout android:layout_width="24dp" @@ -121,7 +146,6 @@ <LinearLayout android:layout_weight="1" - android:id="@+id/mobile_network_list" android:orientation="vertical" android:clickable="false" android:layout_width="wrap_content" @@ -129,28 +153,10 @@ android:gravity="start|center_vertical"> <TextView android:id="@+id/mobile_title" - android:textDirection="locale" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:layout_marginEnd="7dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|start" - android:ellipsize="end" - android:textColor="?android:attr/textColorPrimary" - android:textSize="16sp" - android:fontFamily="google-sans"/> + style="@style/InternetDialog.NetworkTitle"/> <TextView android:id="@+id/mobile_summary" - android:textDirection="locale" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:layout_marginEnd="34dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|start" - android:ellipsize="end" - android:textColor="?android:attr/textColorTertiary" - android:textSize="14sp" - android:fontFamily="google-sans"/> + style="@style/InternetDialog.NetworkSummary"/> </LinearLayout> <FrameLayout @@ -172,17 +178,9 @@ <LinearLayout android:id="@+id/turn_on_wifi_layout" - android:layout_width="match_parent" + style="@style/InternetDialog.Network" android:layout_height="72dp" - android:clickable="true" - android:focusable="true" - android:background="?android:attr/selectableItemBackground" - android:gravity="center" - android:orientation="horizontal" - android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:paddingStart="22dp" - android:paddingEnd="22dp"> + android:gravity="center"> <FrameLayout android:layout_weight="1" @@ -193,13 +191,10 @@ <TextView android:id="@+id/wifi_toggle_title" android:text="@string/turn_on_wifi" - android:textDirection="locale" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="start|center_vertical" - android:textColor="?android:attr/textColorPrimary" - android:textSize="16sp" - android:fontFamily="google-sans"/> + android:textAppearance="@style/TextAppearance.InternetDialog"/> </FrameLayout> <FrameLayout @@ -222,18 +217,12 @@ <LinearLayout android:id="@+id/wifi_connected_layout" - android:layout_width="match_parent" + style="@style/InternetDialog.Network" android:layout_height="72dp" - android:layout_gravity="center_vertical|start" - android:clickable="true" - android:focusable="true" - android:visibility="gone" - android:background="?android:attr/selectableItemBackground" - android:orientation="horizontal" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin" android:paddingStart="20dp" - android:paddingEnd="24dp"> + android:paddingEnd="24dp" + android:background="@drawable/settingslib_switch_bar_bg_on" + android:visibility="gone"> <FrameLayout android:layout_width="24dp" @@ -248,7 +237,6 @@ </FrameLayout> <LinearLayout - android:id="@+id/wifi_connected_list" android:orientation="vertical" android:clickable="false" android:layout_width="wrap_content" @@ -258,26 +246,11 @@ android:gravity="start|center_vertical"> <TextView android:id="@+id/wifi_connected_title" - android:textDirection="locale" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:ellipsize="end" - android:textColor="?android:attr/textColorPrimary" - android:textSize="14sp" - android:fontFamily="google-sans"/> + style="@style/InternetDialog.NetworkTitle.Active" + android:textSize="14sp"/> <TextView android:id="@+id/wifi_connected_summary" - android:textDirection="locale" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin" - android:ellipsize="end" - android:textColor="?android:attr/textColorTertiary" - android:textSize="14sp" - android:fontFamily="google-sans"/> + style="@style/InternetDialog.NetworkSummary.Active"/> </LinearLayout> <FrameLayout @@ -340,13 +313,11 @@ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> <TextView android:text="@string/see_all_networks" - android:textDirection="locale" android:layout_width="wrap_content" android:layout_height="match_parent" android:gravity="start|center_vertical" - android:textColor="?android:attr/textColorPrimary" - android:textSize="14sp" - android:fontFamily="google-sans"/> + android:textAppearance="@style/TextAppearance.InternetDialog" + android:textSize="14sp"/> </FrameLayout> </LinearLayout> @@ -366,7 +337,7 @@ android:textColor="?android:attr/textColorPrimary" android:text="@string/inline_done_button" android:textSize="14sp" - android:fontFamily="google-sans"/> + android:fontFamily="@*android:string/config_headlineFontFamily"/> </FrameLayout> </LinearLayout> </androidx.core.widget.NestedScrollView> diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml index 05352c507e7e..868331ec830f 100644 --- a/packages/SystemUI/res/layout/internet_list_item.xml +++ b/packages/SystemUI/res/layout/internet_list_item.xml @@ -24,21 +24,15 @@ <LinearLayout android:id="@+id/wifi_list" - android:layout_width="match_parent" + style="@style/InternetDialog.Network" android:layout_height="72dp" - android:layout_gravity="center_vertical|start" - android:clickable="true" - android:focusable="true" - android:background="?android:attr/selectableItemBackground" - android:orientation="horizontal" android:paddingStart="20dp" - android:paddingEnd="40dp"> + android:paddingEnd="24dp"> <FrameLayout android:layout_width="24dp" android:layout_height="24dp" android:clickable="false" - android:layout_gravity="center_vertical|start" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + android:layout_gravity="center_vertical|start"> <ImageView android:id="@+id/wifi_icon" android:layout_width="wrap_content" @@ -52,31 +46,16 @@ android:clickable="false" android:layout_width="wrap_content" android:layout_height="72dp" + android:layout_marginEnd="30dp" android:layout_weight="1" - android:gravity="start|center_vertical" - android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"> + android:gravity="start|center_vertical"> <TextView android:id="@+id/wifi_title" - android:textDirection="locale" - android:layout_width="wrap_content" - android:layout_height="20dp" - android:gravity="start|center_vertical" - android:ellipsize="end" - android:textColor="?android:attr/textColorPrimary" - android:textSize="14sp" - android:fontFamily="google-sans" - android:layout_marginEnd="18dp"/> + style="@style/InternetDialog.NetworkTitle" + android:textSize="14sp"/> <TextView android:id="@+id/wifi_summary" - android:textDirection="locale" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:gravity="start|center_vertical" - android:ellipsize="end" - android:textColor="?android:attr/textColorSecondary" - android:textSize="14sp" - android:fontFamily="google-sans" - android:layout_marginEnd="18dp"/> + style="@style/InternetDialog.NetworkSummary"/> </LinearLayout> <FrameLayout diff --git a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml index a21a63c3e7c3..9cf09ff328c4 100644 --- a/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml +++ b/packages/SystemUI/res/layout/keyguard_qs_user_switch.xml @@ -15,19 +15,25 @@ ~ limitations under the License --> <!-- This is a view that shows a user switcher in Keyguard. --> -<com.android.systemui.statusbar.phone.UserAvatarView +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:id="@+id/keyguard_qs_user_switch_view" - android:layout_width="@dimen/kg_framed_avatar_size" - android:layout_height="@dimen/kg_framed_avatar_size" - android:layout_centerHorizontal="true" - android:layout_gravity="top|end" - android:layout_marginEnd="16dp" - systemui:avatarPadding="0dp" - systemui:badgeDiameter="18dp" - systemui:badgeMargin="1dp" - systemui:frameColor="@color/kg_user_avatar_frame" - systemui:framePadding="0dp" - systemui:frameWidth="0dp"> -</com.android.systemui.statusbar.phone.UserAvatarView> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="end"> + <com.android.systemui.statusbar.phone.UserAvatarView + android:id="@+id/kg_multi_user_avatar" + android:layout_width="@dimen/kg_framed_avatar_size" + android:layout_height="@dimen/kg_framed_avatar_size" + android:layout_centerHorizontal="true" + android:layout_gravity="top|end" + android:layout_marginEnd="16dp" + systemui:avatarPadding="0dp" + systemui:badgeDiameter="18dp" + systemui:badgeMargin="1dp" + systemui:frameColor="@color/kg_user_avatar_frame" + systemui:framePadding="0dp" + systemui:frameWidth="0dp"> + </com.android.systemui.statusbar.phone.UserAvatarView> +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml index 687830d5c7b3..0fcbfa161ddf 100644 --- a/packages/SystemUI/res/layout/udfps_view.xml +++ b/packages/SystemUI/res/layout/udfps_view.xml @@ -20,7 +20,7 @@ android:id="@+id/udfps_view" android:layout_width="match_parent" android:layout_height="match_parent" - systemui:sensorTouchAreaCoefficient="0.75" + systemui:sensorTouchAreaCoefficient="1.0" android:contentDescription="@string/accessibility_fingerprint_label"> <ViewStub diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml index 461505f12ce6..ffcc3a821d36 100644 --- a/packages/SystemUI/res/values-night/styles.xml +++ b/packages/SystemUI/res/values-night/styles.xml @@ -48,4 +48,16 @@ <item name="android:windowLightStatusBar">false</item> </style> + <style name="TextAppearance.InternetDialog.Active"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textSize">16sp</item> + <item name="android:textColor">@color/connected_network_primary_color</item> + <item name="android:textDirection">locale</item> + </style> + + <style name="TextAppearance.InternetDialog.Secondary.Active"> + <item name="android:textSize">14sp</item> + <item name="android:textColor">@color/connected_network_secondary_color</item> + </style> + </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 19633f2492cf..f539b0cf68a1 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -190,9 +190,6 @@ <color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 --> <color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 --> - <!-- Logout button --> - <color name="logout_button_bg_color">#ccffffff</color> - <!-- Color for the Assistant invocation lights --> <color name="default_invocation_lights_color">#ffffffff</color> <!-- white --> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index b6d5b3a6760a..d274c917c26d 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -194,11 +194,6 @@ low powered state yet. --> <bool name="doze_long_press_uses_prox">true</bool> - <!-- Doze: whether the brightness sensor uses the proximity sensor. - If both this parameter and doze_selectively_register_prox are true, registration for the - brightness sensor won't occur when the display state is ON. --> - <bool name="doze_brightness_uses_prox">true</bool> - <!-- Doze: should notifications be used as a pulse signal? --> <bool name="doze_pulse_on_notifications">true</bool> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 15f209e557dd..f76f7d8de2d1 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1242,10 +1242,7 @@ <integer name="wired_charging_keyguard_text_animation_distance">-30</integer> <!-- Logout button --> - <dimen name="logout_button_layout_height">32dp</dimen> - <dimen name="logout_button_padding_horizontal">16dp</dimen> - <dimen name="logout_button_margin_bottom">12dp</dimen> - <dimen name="logout_button_corner_radius">4dp</dimen> + <dimen name="logout_button_corner_radius">50dp</dimen> <!-- Blur radius on status bar window and power menu --> <dimen name="min_window_blur_radius">1px</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ebf6e4888de4..6019b0e9ed9e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3027,4 +3027,6 @@ <string name="wifi_failed_connect_message">Failed to connect to network</string> <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] --> <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> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index d25474255bfc..8a809e46fe99 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -951,4 +951,60 @@ <item name="android:maxHeight">4dp</item> </style> + <!-- Internet Dialog --> + <style name="InternetDialog"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:layout_gravity">center_vertical|start</item> + <item name="android:layout_marginStart">@dimen/internet_dialog_network_layout_margin</item> + </style> + + <style name="InternetDialog.Network"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">88dp</item> + <item name="android:layout_marginEnd">@dimen/internet_dialog_network_layout_margin</item> + <item name="android:paddingStart">22dp</item> + <item name="android:paddingEnd">22dp</item> + <item name="android:orientation">horizontal</item> + <item name="android:focusable">true</item> + <item name="android:clickable">true</item> + </style> + + <style name="InternetDialog.NetworkTitle"> + <item name="android:layout_marginEnd">7dp</item> + <item name="android:ellipsize">end</item> + <item name="android:textAppearance">@style/TextAppearance.InternetDialog</item> + </style> + + <style name="InternetDialog.NetworkTitle.Active"> + <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Active</item> + </style> + + <style name="InternetDialog.NetworkSummary"> + <item name="android:layout_marginEnd">34dp</item> + <item name="android:ellipsize">end</item> + <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary</item> + </style> + + <style name="InternetDialog.NetworkSummary.Active"> + <item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary.Active + </item> + </style> + + <style name="TextAppearance.InternetDialog"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> + <item name="android:textSize">16sp</item> + <item name="android:textColor">?android:attr/textColorPrimary</item> + <item name="android:textDirection">locale</item> + </style> + + <style name="TextAppearance.InternetDialog.Secondary"> + <item name="android:textSize">14sp</item> + <item name="android:textColor">?android:attr/textColorTertiary</item> + </style> + + <style name="TextAppearance.InternetDialog.Active"/> + + <style name="TextAppearance.InternetDialog.Secondary.Active"/> + </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java index 92f89d6b90fd..efcf40a66258 100644 --- a/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java +++ b/packages/SystemUI/src/com/android/keyguard/AnimatableClockController.java @@ -160,9 +160,7 @@ public class AnimatableClockController extends ViewController<AnimatableClockVie mBroadcastDispatcher.unregisterReceiver(mLocaleBroadcastReceiver); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback); mBatteryController.removeCallback(mBatteryCallback); - if (!mView.isAttachedToWindow()) { - mStatusBarStateController.removeCallback(mStatusBarStatePersistentListener); - } + mStatusBarStateController.removeCallback(mStatusBarStatePersistentListener); } /** Animate the clock appearance */ diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java index 3a0357d2a284..4331f52eb1a2 100644 --- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardQsUserSwitchComponent.java @@ -16,7 +16,8 @@ package com.android.keyguard.dagger; -import com.android.systemui.statusbar.phone.UserAvatarView; +import android.widget.FrameLayout; + import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController; import dagger.BindsInstance; @@ -31,8 +32,7 @@ public interface KeyguardQsUserSwitchComponent { /** Simple factory for {@link KeyguardUserSwitcherComponent}. */ @Subcomponent.Factory interface Factory { - KeyguardQsUserSwitchComponent build( - @BindsInstance UserAvatarView userAvatarView); + KeyguardQsUserSwitchComponent build(@BindsInstance FrameLayout userAvatarContainer); } /** Builds a {@link KeyguardQsUserSwitchController}. */ diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index c8f8404ff0d6..8379ccf3154a 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -120,15 +120,16 @@ public class ImageWallpaper extends WallpaperService { @Override public void onCreate(SurfaceHolder surfaceHolder) { + Trace.beginSection("ImageWallpaper.Engine#onCreate"); mEglHelper = getEglHelperInstance(); // Deferred init renderer because we need to get wallpaper by display context. mRenderer = getRendererInstance(); setFixedSizeAllowed(true); updateSurfaceSize(); - mRenderer.setOnBitmapChanged(this::updateMiniBitmap); getDisplayContext().getSystemService(DisplayManager.class) .registerDisplayListener(this, mWorker.getThreadHandler()); + Trace.endSection(); } @Override @@ -198,15 +199,22 @@ public class ImageWallpaper extends WallpaperService { } @Override + public boolean shouldWaitForEngineShown() { + return true; + } + + @Override public void onDestroy() { getDisplayContext().getSystemService(DisplayManager.class) .unregisterDisplayListener(this); mMiniBitmap = null; mWorker.getThreadHandler().post(() -> { + Trace.beginSection("ImageWallpaper.Engine#onDestroy"); mRenderer.finish(); mRenderer = null; mEglHelper.finish(); mEglHelper = null; + Trace.endSection(); }); } @@ -340,8 +348,10 @@ public class ImageWallpaper extends WallpaperService { public void onSurfaceCreated(SurfaceHolder holder) { if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { + Trace.beginSection("ImageWallpaper#onSurfaceCreated"); mEglHelper.init(holder, needSupportWideColorGamut()); mRenderer.onSurfaceCreated(); + Trace.endSection(); }); } @@ -358,9 +368,11 @@ public class ImageWallpaper extends WallpaperService { } private void drawFrame() { + Trace.beginSection("ImageWallpaper#drawFrame"); preRender(); requestRender(); postRender(); + Trace.endSection(); } public void preRender() { @@ -427,6 +439,7 @@ public class ImageWallpaper extends WallpaperService { // This method should only be invoked from worker thread. Trace.beginSection("ImageWallpaper#postRender"); scheduleFinishRendering(); + reportEngineShown(false /* waitForEngineShown */); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt index 9c818fff5018..2630f119de00 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt @@ -16,6 +16,7 @@ package com.android.systemui.biometrics +import android.animation.ValueAnimator import android.content.Context import android.content.res.Configuration import android.graphics.PointF @@ -26,6 +27,8 @@ import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.settingslib.Utils import com.android.systemui.R +import com.android.systemui.animation.Interpolators +import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.statusbar.CircleReveal import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.statusbar.NotificationShadeWindowController @@ -36,10 +39,14 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.ViewController import java.io.PrintWriter import javax.inject.Inject import javax.inject.Provider +import com.android.systemui.plugins.statusbar.StatusBarStateController + +private const val WAKE_AND_UNLOCK_FADE_DURATION = 180L /*** * Controls the ripple effect that shows when authentication is successful. @@ -52,20 +59,30 @@ class AuthRippleController @Inject constructor( private val authController: AuthController, private val configurationController: ConfigurationController, private val keyguardUpdateMonitor: KeyguardUpdateMonitor, + private val keyguardStateController: KeyguardStateController, + private val wakefulnessLifecycle: WakefulnessLifecycle, private val commandRegistry: CommandRegistry, private val notificationShadeWindowController: NotificationShadeWindowController, private val bypassController: KeyguardBypassController, private val biometricUnlockController: BiometricUnlockController, private val udfpsControllerProvider: Provider<UdfpsController>, + private val statusBarStateController: StatusBarStateController, rippleView: AuthRippleView? -) : ViewController<AuthRippleView>(rippleView) { +) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback, + WakefulnessLifecycle.Observer { + + @VisibleForTesting + internal var startLightRevealScrimOnKeyguardFadingAway = false var fingerprintSensorLocation: PointF? = null private var faceSensorLocation: PointF? = null private var circleReveal: LightRevealEffect? = null private var udfpsController: UdfpsController? = null + private var dwellScale = 2f private var expandedDwellScale = 2.5f + private var aodDwellScale = 1.9f + private var aodExpandedDwellScale = 2.3f private var udfpsRadius: Float = -1f override fun onInit() { @@ -82,6 +99,8 @@ class AuthRippleController @Inject constructor( udfpsController?.addCallback(udfpsControllerCallback) configurationController.addCallback(configurationChangedListener) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) + keyguardStateController.addCallback(this) + wakefulnessLifecycle.addObserver(this) commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() } } @@ -91,6 +110,8 @@ class AuthRippleController @Inject constructor( authController.removeCallback(authControllerCallback) keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback) configurationController.removeCallback(configurationChangedListener) + keyguardStateController.removeCallback(this) + wakefulnessLifecycle.removeObserver(this) commandRegistry.unregisterCommand("auth-ripple") notificationShadeWindowController.setForcePluginOpen(false, this) @@ -118,30 +139,48 @@ class AuthRippleController @Inject constructor( private fun showUnlockedRipple() { notificationShadeWindowController.setForcePluginOpen(true, this) - val biometricUnlockMode = biometricUnlockController.mode - val useCircleReveal = circleReveal != null && - (biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK || - biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING || - biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM) + val useCircleReveal = circleReveal != null && biometricUnlockController.isWakeAndUnlock val lightRevealScrim = statusBar.lightRevealScrim if (useCircleReveal) { lightRevealScrim?.revealEffect = circleReveal!! + startLightRevealScrimOnKeyguardFadingAway = true } mView.startUnlockedRipple( /* end runnable */ Runnable { notificationShadeWindowController.setForcePluginOpen(false, this) - }, - /* circleReveal */ - if (useCircleReveal) { - lightRevealScrim - } else { - null } ) } + override fun onKeyguardFadingAwayChanged() { + if (keyguardStateController.isKeyguardFadingAway) { + val lightRevealScrim = statusBar.lightRevealScrim + if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) { + val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply { + interpolator = Interpolators.LINEAR_OUT_SLOW_IN + duration = RIPPLE_ANIMATION_DURATION + startDelay = keyguardStateController.keyguardFadingAwayDelay + addUpdateListener { animator -> + if (lightRevealScrim.revealEffect != circleReveal) { + // if the something else took over the reveal, let's do nothing. + return@addUpdateListener + } + lightRevealScrim.revealAmount = animator.animatedValue as Float + } + } + revealAnimator.start() + startLightRevealScrimOnKeyguardFadingAway = false + } + } + } + + override fun onStartedGoingToSleep() { + // reset the light reveal start in case we were pending an unlock + startLightRevealScrimOnKeyguardFadingAway = false + } + fun updateSensorLocation() { fingerprintSensorLocation = authController.fingerprintSensorLocation faceSensorLocation = authController.faceAuthSensorLocation @@ -163,6 +202,22 @@ class AuthRippleController @Inject constructor( Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor) } + private fun showDwellRipple() { + if (statusBarStateController.isDozing) { + mView.startDwellRipple( + /* startRadius */ udfpsRadius, + /* endRadius */ udfpsRadius * aodDwellScale, + /* expandedRadius */ udfpsRadius * aodExpandedDwellScale, + /* isDozing */ true) + } else { + mView.startDwellRipple( + /* startRadius */ udfpsRadius, + /* endRadius */ udfpsRadius * dwellScale, + /* expandedRadius */ udfpsRadius * expandedDwellScale, + /* isDozing */ false) + } + } + private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { override fun onBiometricAuthenticated( @@ -204,10 +259,7 @@ class AuthRippleController @Inject constructor( } mView.setSensorLocation(fingerprintSensorLocation!!) - mView.startDwellRipple( - /* startRadius */ udfpsRadius, - /* endRadius */ udfpsRadius * dwellScale, - /* expandedRadius */ udfpsRadius * expandedDwellScale) + showDwellRipple() } override fun onFingerUp() { @@ -234,14 +286,18 @@ class AuthRippleController @Inject constructor( } inner class AuthRippleCommand : Command { - fun printDwellInfo(pw: PrintWriter) { - pw.println("dwell ripple: " + + fun printLockScreenDwellInfo(pw: PrintWriter) { + pw.println("lock screen dwell ripple: " + "\n\tsensorLocation=$fingerprintSensorLocation" + "\n\tdwellScale=$dwellScale" + - "\n\tdwellAlpha=${mView.dwellAlpha}, " + - "duration=${mView.dwellAlphaDuration}" + - "\n\tdwellExpand=$expandedDwellScale" + - "\n\t(crash systemui to reset to default)") + "\n\tdwellExpand=$expandedDwellScale") + } + + fun printAodDwellInfo(pw: PrintWriter) { + pw.println("aod dwell ripple: " + + "\n\tsensorLocation=$fingerprintSensorLocation" + + "\n\tdwellScale=$aodDwellScale" + + "\n\tdwellExpand=$aodExpandedDwellScale") } override fun execute(pw: PrintWriter, args: List<String>) { @@ -249,40 +305,12 @@ class AuthRippleController @Inject constructor( invalidCommand(pw) } else { when (args[0]) { - "dwellScale" -> { - if (args.size > 1 && args[1].toFloatOrNull() != null) { - dwellScale = args[1].toFloat() - printDwellInfo(pw) - } else { - pw.println("expected float argument <dwellScale>") - } - } - "dwellAlpha" -> { - if (args.size > 2 && args[1].toFloatOrNull() != null && - args[2].toLongOrNull() != null) { - mView.dwellAlpha = args[1].toFloat() - if (args[2].toFloat() > 200L) { - pw.println("alpha animation duration must be less than 200ms.") - } - mView.dwellAlphaDuration = kotlin.math.min(args[2].toLong(), 200L) - printDwellInfo(pw) + "dwell" -> { + showDwellRipple() + if (statusBarStateController.isDozing) { + printAodDwellInfo(pw) } else { - pw.println("expected two float arguments:" + - " <dwellAlpha> <dwellAlphaDuration>") - } - } - "dwellExpand" -> { - if (args.size > 1 && args[1].toFloatOrNull() != null) { - val expandedScale = args[1].toFloat() - if (expandedScale <= dwellScale) { - pw.println("invalid expandedScale. must be greater than " + - "dwellScale=$dwellScale, but given $expandedScale") - } else { - expandedDwellScale = expandedScale - } - printDwellInfo(pw) - } else { - pw.println("expected float argument <expandedScale>") + printLockScreenDwellInfo(pw) } } "fingerprint" -> { @@ -313,9 +341,7 @@ class AuthRippleController @Inject constructor( override fun help(pw: PrintWriter) { pw.println("Usage: adb shell cmd statusbar auth-ripple <command>") pw.println("Available commands:") - pw.println(" dwellScale <200ms_scale: float>") - pw.println(" dwellAlpha <alpha: float> <duration : long>") - pw.println(" dwellExpand <expanded_scale: float>") + pw.println(" dwell") pw.println(" fingerprint") pw.println(" face") pw.println(" custom <x-location: int> <y-location: int>") @@ -326,4 +352,8 @@ class AuthRippleController @Inject constructor( help(pw) } } + + companion object { + const val RIPPLE_ANIMATION_DURATION: Long = 1533 + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt index 8e1303713171..c6d26ffb9957 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt @@ -26,13 +26,10 @@ import android.graphics.PointF import android.util.AttributeSet import android.view.View import android.view.animation.PathInterpolator -import com.android.internal.R.attr.interpolator import com.android.internal.graphics.ColorUtils import com.android.systemui.animation.Interpolators -import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.charging.RippleShader -private const val RIPPLE_ANIMATION_DURATION: Long = 1533 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f /** @@ -45,12 +42,18 @@ private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f */ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) { private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f) - private val dwellPulseDuration = 200L - var dwellAlphaDuration = dwellPulseDuration + + private val dwellPulseDuration = 50L + private val dwellAlphaDuration = dwellPulseDuration + private val dwellAlpha: Float = 1f private val dwellExpandDuration = 1200L - dwellPulseDuration - private val retractDuration = 400L - var dwellAlpha: Float = .5f + private val aodDwellPulseDuration = 50L + private var aodDwellAlphaDuration = aodDwellPulseDuration + private var aodDwellAlpha: Float = .8f + private var aodDwellExpandDuration = 1200L - aodDwellPulseDuration + + private val retractDuration = 400L private var alphaInDuration: Long = 0 private var unlockedRippleInProgress: Boolean = false private val rippleShader = RippleShader() @@ -142,7 +145,12 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at * Ripple that moves animates from an outer ripple ring of * startRadius => endRadius => expandedRadius */ - fun startDwellRipple(startRadius: Float, endRadius: Float, expandedRadius: Float) { + fun startDwellRipple( + startRadius: Float, + endRadius: Float, + expandedRadius: Float, + isDozing: Boolean + ) { if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) { return } @@ -153,12 +161,13 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val endInitialDwellProgress = endRadius / radius / 4f val endExpandDwellProgress = expandedRadius / radius / 4f - val pulseOutEndAlpha = (255 * dwellAlpha).toInt() - val expandDwellEndAlpha = kotlin.math.min((255 * (dwellAlpha + .25f)).toInt(), 255) + val alpha = if (isDozing) aodDwellAlpha else dwellAlpha + val pulseOutEndAlpha = (255 * alpha).toInt() + val expandDwellEndAlpha = kotlin.math.min((255 * (alpha + .25f)).toInt(), 255) val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(startDwellProgress, endInitialDwellProgress).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN - duration = dwellPulseDuration + duration = if (isDozing) aodDwellPulseDuration else dwellPulseDuration addUpdateListener { animator -> val now = animator.currentPlayTime rippleShader.progress = animator.animatedValue as Float @@ -170,7 +179,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val dwellPulseOutAlphaAnimator = ValueAnimator.ofInt(0, pulseOutEndAlpha).apply { interpolator = Interpolators.LINEAR - duration = dwellAlphaDuration + duration = if (isDozing) aodDwellAlphaDuration else dwellAlphaDuration addUpdateListener { animator -> rippleShader.color = ColorUtils.setAlphaComponent( rippleShader.color, @@ -184,7 +193,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val expandDwellRippleAnimator = ValueAnimator.ofFloat(endInitialDwellProgress, endExpandDwellProgress).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN - duration = dwellExpandDuration + duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration addUpdateListener { animator -> val now = animator.currentPlayTime rippleShader.progress = animator.animatedValue as Float @@ -197,7 +206,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val expandDwellAlphaAnimator = ValueAnimator.ofInt(pulseOutEndAlpha, expandDwellEndAlpha) .apply { interpolator = Interpolators.LINEAR - duration = dwellExpandDuration + duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration addUpdateListener { animator -> rippleShader.color = ColorUtils.setAlphaComponent( rippleShader.color, @@ -238,7 +247,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at /** * Ripple that bursts outwards from the position of the sensor to the edges of the screen */ - fun startUnlockedRipple(onAnimationEnd: Runnable?, lightReveal: LightRevealScrim?) { + fun startUnlockedRipple(onAnimationEnd: Runnable?) { if (unlockedRippleInProgress) { return // Ignore if ripple effect is already playing } @@ -254,7 +263,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val rippleAnimator = ValueAnimator.ofFloat(rippleStart, 1f).apply { interpolator = Interpolators.LINEAR_OUT_SLOW_IN - duration = RIPPLE_ANIMATION_DURATION + duration = AuthRippleController.RIPPLE_ANIMATION_DURATION addUpdateListener { animator -> val now = animator.currentPlayTime rippleShader.progress = animator.animatedValue as Float @@ -264,14 +273,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at } } - val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply { - interpolator = rippleAnimator.interpolator - duration = rippleAnimator.duration - addUpdateListener { animator -> - lightReveal?.revealAmount = animator.animatedValue as Float - } - } - val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply { duration = alphaDuration addUpdateListener { animator -> @@ -286,7 +287,6 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at val animatorSet = AnimatorSet().apply { playTogether( rippleAnimator, - revealAnimator, alphaInAnimator ) addListener(object : AnimatorListenerAdapter() { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index 52c26e1c20e6..9f8990f87d1e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -39,7 +39,6 @@ import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.media.AudioAttributes; import android.os.Handler; -import android.os.Looper; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -63,7 +62,6 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.dump.DumpManager; -import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -71,6 +69,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -93,7 +92,7 @@ import kotlin.Unit; * controls/manages all UDFPS sensors. In other words, a single controller is registered with * {@link com.android.server.biometrics.sensors.fingerprint.FingerprintService}, and interfaces such * as {@link FingerprintManager#onPointerDown(int, int, int, float, float)} or - * {@link IUdfpsOverlayController#showUdfpsOverlay(int)}should all have + * {@link IUdfpsOverlayController#showUdfpsOverlay(int)} should all have * {@code sensorId} parameters. */ @SuppressWarnings("deprecation") @@ -117,9 +116,7 @@ public class UdfpsController implements DozeReceiver { @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; @NonNull private final DumpManager mDumpManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - @NonNull private final KeyguardViewMediator mKeyguardViewMediator; @Nullable private final Vibrator mVibrator; - @NonNull private final Handler mMainHandler; @NonNull private final FalsingManager mFalsingManager; @NonNull private final PowerManager mPowerManager; @NonNull private final AccessibilityManager mAccessibilityManager; @@ -128,6 +125,8 @@ public class UdfpsController implements DozeReceiver { @NonNull private final KeyguardBypassController mKeyguardBypassController; @NonNull private final ConfigurationController mConfigurationController; @NonNull private final SystemClock mSystemClock; + @NonNull private final UnlockedScreenOffAnimationController + mUnlockedScreenOffAnimationController; @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener; // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple // sensors, this, in addition to a lot of the code here, will be updated. @@ -517,7 +516,6 @@ public class UdfpsController implements DozeReceiver { @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull DumpManager dumpManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, - @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull FalsingManager falsingManager, @NonNull PowerManager powerManager, @NonNull AccessibilityManager accessibilityManager, @@ -531,11 +529,11 @@ public class UdfpsController implements DozeReceiver { @NonNull DisplayManager displayManager, @Main Handler mainHandler, @NonNull ConfigurationController configurationController, - @NonNull SystemClock systemClock) { + @NonNull SystemClock systemClock, + @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) { mContext = context; mExecution = execution; // TODO (b/185124905): inject main handler and vibrator once done prototyping - mMainHandler = new Handler(Looper.getMainLooper()); mVibrator = vibrator; mInflater = inflater; // The fingerprint manager is queried for UDFPS before this class is constructed, so the @@ -549,7 +547,6 @@ public class UdfpsController implements DozeReceiver { mKeyguardViewManager = statusBarKeyguardViewManager; mDumpManager = dumpManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mKeyguardViewMediator = keyguardViewMediator; mFalsingManager = falsingManager; mPowerManager = powerManager; mAccessibilityManager = accessibilityManager; @@ -568,6 +565,7 @@ public class UdfpsController implements DozeReceiver { mKeyguardBypassController = keyguardBypassController; mConfigurationController = configurationController; mSystemClock = systemClock; + mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; mSensorProps = findFirstUdfps(); // At least one UDFPS sensor exists @@ -657,6 +655,20 @@ public class UdfpsController implements DozeReceiver { } } + private boolean shouldRotate(@Nullable UdfpsAnimationViewController animation) { + if (!(animation instanceof UdfpsKeyguardViewController)) { + // always rotate view if we're not on the keyguard + return true; + } + + // on the keyguard, make sure we don't rotate if we're going to sleep or not occluded + if (mKeyguardUpdateMonitor.isGoingToSleep() || !mKeyguardStateController.isOccluded()) { + return false; + } + + return true; + } + private WindowManager.LayoutParams computeLayoutParams( @Nullable UdfpsAnimationViewController animation) { final int paddingX = animation != null ? animation.getPaddingX() : 0; @@ -680,9 +692,11 @@ public class UdfpsController implements DozeReceiver { // Transform dimensions if the device is in landscape mode switch (mContext.getDisplay().getRotation()) { case Surface.ROTATION_90: - if (animation instanceof UdfpsKeyguardViewController - && mKeyguardUpdateMonitor.isGoingToSleep()) { + if (!shouldRotate(animation)) { + Log.v(TAG, "skip rotating udfps location ROTATION_90"); break; + } else { + Log.v(TAG, "rotate udfps location ROTATION_90"); } mCoreLayoutParams.x = mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingX; @@ -691,9 +705,11 @@ public class UdfpsController implements DozeReceiver { break; case Surface.ROTATION_270: - if (animation instanceof UdfpsKeyguardViewController - && mKeyguardUpdateMonitor.isGoingToSleep()) { + if (!shouldRotate(animation)) { + Log.v(TAG, "skip rotating udfps location ROTATION_270"); break; + } else { + Log.v(TAG, "rotate udfps location ROTATION_270"); } mCoreLayoutParams.x = p.x - mSensorProps.sensorLocationY - mSensorProps.sensorRadius - paddingX; @@ -790,13 +806,12 @@ public class UdfpsController implements DozeReceiver { mStatusBar, mKeyguardViewManager, mKeyguardUpdateMonitor, - mFgExecutor, mDumpManager, - mKeyguardViewMediator, mLockscreenShadeTransitionController, mConfigurationController, mSystemClock, mKeyguardStateController, + mUnlockedScreenOffAnimationController, this ); case IUdfpsOverlayController.REASON_AUTH_BP: diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java index f1cb3a78e2fe..c128e5e2ab30 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java @@ -26,16 +26,15 @@ import android.view.MotionEvent; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.dump.DumpManager; -import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.time.SystemClock; import java.io.FileDescriptor; @@ -47,13 +46,13 @@ import java.io.PrintWriter; public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> { @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; - @NonNull private final DelayableExecutor mExecutor; - @NonNull private final KeyguardViewMediator mKeyguardViewMediator; @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController; @NonNull private final ConfigurationController mConfigurationController; @NonNull private final SystemClock mSystemClock; @NonNull private final KeyguardStateController mKeyguardStateController; @NonNull private final UdfpsController mUdfpsController; + @NonNull private final UnlockedScreenOffAnimationController + mUnlockedScreenOffAnimationController; private boolean mShowingUdfpsBouncer; private boolean mUdfpsRequested; @@ -80,24 +79,22 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud @NonNull StatusBar statusBar, @NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager, @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor, - @NonNull DelayableExecutor mainDelayableExecutor, @NonNull DumpManager dumpManager, - @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull LockscreenShadeTransitionController transitionController, @NonNull ConfigurationController configurationController, @NonNull SystemClock systemClock, @NonNull KeyguardStateController keyguardStateController, + @NonNull UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, @NonNull UdfpsController udfpsController) { super(view, statusBarStateController, statusBar, dumpManager); mKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mExecutor = mainDelayableExecutor; - mKeyguardViewMediator = keyguardViewMediator; mLockScreenShadeTransitionController = transitionController; mConfigurationController = configurationController; mSystemClock = systemClock; mKeyguardStateController = keyguardStateController; mUdfpsController = udfpsController; + mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; } @Override @@ -134,6 +131,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor); mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this); + mUnlockedScreenOffAnimationController.addCallback(mUnlockedScreenOffCallback); } @Override @@ -150,6 +148,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) { mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null); } + mUnlockedScreenOffAnimationController.removeCallback(mUnlockedScreenOffCallback); } @Override @@ -422,4 +421,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud updatePauseAuth(); } }; + + private final UnlockedScreenOffAnimationController.Callback mUnlockedScreenOffCallback = + (linear, eased) -> mStateListener.onDozeAmountChanged(linear, eased); } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt index 4104e3184efd..46a03e809b06 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt @@ -16,6 +16,10 @@ package com.android.systemui.controls.ui +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.Bundle import android.view.View import android.view.ViewGroup @@ -23,18 +27,25 @@ import android.view.WindowInsets import android.view.WindowInsets.Type import com.android.systemui.R +import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.controls.management.ControlsAnimations import com.android.systemui.util.LifecycleActivity import javax.inject.Inject /** - * Displays Device Controls inside an activity + * Displays Device Controls inside an activity. This activity is available to be displayed over the + * lockscreen if the user has allowed it via + * [android.provider.Settings.Secure.LOCKSCREEN_SHOW_CONTROLS]. This activity will be + * destroyed on SCREEN_OFF events, due to issues with occluded activities over lockscreen as well as + * user expectations for the activity to not continue running. */ class ControlsActivity @Inject constructor( - private val uiController: ControlsUiController + private val uiController: ControlsUiController, + private val broadcastDispatcher: BroadcastDispatcher ) : LifecycleActivity() { private lateinit var parent: ViewGroup + private lateinit var broadcastReceiver: BroadcastReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -62,6 +73,8 @@ class ControlsActivity @Inject constructor( WindowInsets.CONSUMED } } + + initBroadcastReceiver() } override fun onResume() { @@ -83,4 +96,25 @@ class ControlsActivity @Inject constructor( uiController.hide() } + + override fun onDestroy() { + super.onDestroy() + + broadcastDispatcher.unregisterReceiver(broadcastReceiver) + } + + private fun initBroadcastReceiver() { + broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = intent.getAction() + if (Intent.ACTION_SCREEN_OFF.equals(action)) { + finish() + } + } + } + + val filter = IntentFilter() + filter.addAction(Intent.ACTION_SCREEN_OFF) + broadcastDispatcher.registerReceiver(broadcastReceiver, filter) + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 567d0cb3e6cb..72da7f4f893a 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -256,13 +256,13 @@ class ControlsUiControllerImpl @Inject constructor ( // Force animations when transitioning from a dialog to an activity intent.putExtra(ControlsUiController.EXTRA_ANIMATE, true) - if (keyguardStateController.isUnlocked()) { + if (keyguardStateController.isShowing()) { + activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */) + } else { activityContext.startActivity( intent, ActivityOptions.makeSceneTransitionAnimation(activityContext as Activity).toBundle() ) - } else { - activityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */) } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java index 41964652ac49..845d7dc26ee5 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java @@ -214,6 +214,14 @@ public class DozeLog implements Dumpable { } /** + * Appends display state delayed by UDFPS event to the logs + * @param delayedDisplayState the display screen state that was delayed + */ + public void traceDisplayStateDelayedByUdfps(int delayedDisplayState) { + mLogger.logDisplayStateDelayedByUdfps(delayedDisplayState); + } + + /** * Appends display state changed event to the logs * @param displayState new DozeMachine state */ @@ -267,6 +275,13 @@ public class DozeLog implements Dumpable { } /** + * Appends sensor event dropped event to logs + */ + public void traceSensorEventDropped(int sensorEvent, String reason) { + mLogger.logSensorEventDropped(sensorEvent, reason); + } + + /** * Appends pulse dropped event to logs * @param reason why the pulse was dropped */ diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt index 9bc74be9b9c3..dc186182432f 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt @@ -160,6 +160,14 @@ class DozeLogger @Inject constructor( }) } + fun logDisplayStateDelayedByUdfps(delayedDisplayState: Int) { + buffer.log(TAG, INFO, { + str1 = Display.stateToString(delayedDisplayState) + }, { + "Delaying display state change to: $str1 due to UDFPS activity" + }) + } + fun logDisplayStateChanged(displayState: Int) { buffer.log(TAG, INFO, { str1 = Display.stateToString(displayState) @@ -197,6 +205,15 @@ class DozeLogger @Inject constructor( }) } + fun logSensorEventDropped(sensorEvent: Int, reason: String) { + buffer.log(TAG, INFO, { + int1 = sensorEvent + str1 = reason + }, { + "SensorEvent [$int1] dropped, reason=$str1" + }) + } + fun logPulseDropped(reason: String) { buffer.log(TAG, INFO, { str1 = reason diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 98d2739836a9..da7b389fbd36 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -29,7 +29,6 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; -import android.view.Display; import com.android.systemui.dock.DockManager; import com.android.systemui.doze.dagger.BrightnessSensor; @@ -111,7 +110,15 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) { switch (newState) { case INITIALIZED: + resetBrightnessToDefault(); + break; + case DOZE_AOD: + case DOZE_REQUEST_PULSE: + case DOZE_AOD_DOCKED: + setLightSensorEnabled(true); + break; case DOZE: + setLightSensorEnabled(false); resetBrightnessToDefault(); break; case FINISH: @@ -124,22 +131,6 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi } } - @Override - public void onScreenState(int state) { - boolean isDockedScreenOn = state == Display.STATE_ON && mDockManager.isDocked(); - if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND - || (isDockedScreenOn && shouldRegisterLightSensorWhenScreenOnDocked())) { - setLightSensorEnabled(true); - } else { - setLightSensorEnabled(false); - } - } - - private boolean shouldRegisterLightSensorWhenScreenOnDocked() { - return !mDozeParameters.brightnessUsesProx() - || !mDozeParameters.getSelectivelyRegisterSensorsUsingProx(); - } - private void onDestroy() { setLightSensorEnabled(false); } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java index 8c50a16b566f..8f1486b0c7cb 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java @@ -26,6 +26,11 @@ import android.os.Handler; import android.util.Log; import android.view.Display; +import androidx.annotation.Nullable; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.biometrics.AuthController; +import com.android.systemui.biometrics.UdfpsController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.doze.dagger.WrappedService; @@ -34,6 +39,7 @@ import com.android.systemui.util.wakelock.SettableWakeLock; import com.android.systemui.util.wakelock.WakeLock; import javax.inject.Inject; +import javax.inject.Provider; /** * Controls the screen when dozing. @@ -56,23 +62,61 @@ public class DozeScreenState implements DozeMachine.Part { */ public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2500; + /** + * Add an extra delay to the transition to DOZE when udfps is current activated before + * the display state transitions from ON => DOZE. + */ + public static final int UDFPS_DISPLAY_STATE_DELAY = 1200; + private final DozeMachine.Service mDozeService; private final Handler mHandler; private final Runnable mApplyPendingScreenState = this::applyPendingScreenState; private final DozeParameters mParameters; private final DozeHost mDozeHost; + private final AuthController mAuthController; + private final Provider<UdfpsController> mUdfpsControllerProvider; + @Nullable private UdfpsController mUdfpsController; + private final DozeLog mDozeLog; private int mPendingScreenState = Display.STATE_UNKNOWN; private SettableWakeLock mWakeLock; @Inject - public DozeScreenState(@WrappedService DozeMachine.Service service, @Main Handler handler, - DozeHost host, DozeParameters parameters, WakeLock wakeLock) { + public DozeScreenState( + @WrappedService DozeMachine.Service service, + @Main Handler handler, + DozeHost host, + DozeParameters parameters, + WakeLock wakeLock, + AuthController authController, + Provider<UdfpsController> udfpsControllerProvider, + DozeLog dozeLog) { mDozeService = service; mHandler = handler; mParameters = parameters; mDozeHost = host; mWakeLock = new SettableWakeLock(wakeLock, TAG); + mAuthController = authController; + mUdfpsControllerProvider = udfpsControllerProvider; + mDozeLog = dozeLog; + + updateUdfpsController(); + if (mUdfpsController == null) { + mAuthController.addCallback(new AuthController.Callback() { + @Override + public void onAllAuthenticatorsRegistered() { + updateUdfpsController(); + } + }); + } + } + + private void updateUdfpsController() { + if (mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) { + mUdfpsController = mUdfpsControllerProvider.get(); + } else { + mUdfpsController = null; + } } @Override @@ -110,21 +154,28 @@ public class DozeScreenState implements DozeMachine.Part { mPendingScreenState = screenState; // Delay screen state transitions even longer while animations are running. - boolean shouldDelayTransition = newState == DOZE_AOD + boolean shouldDelayTransitionEnteringDoze = newState == DOZE_AOD && mParameters.shouldControlScreenOff() && !turningOn; - if (shouldDelayTransition) { + // Delay screen state transition longer if UDFPS is actively authenticating a fp + boolean shouldDelayTransitionForUDFPS = newState == DOZE_AOD + && mUdfpsController != null && mUdfpsController.isFingerDown(); + + if (shouldDelayTransitionEnteringDoze || shouldDelayTransitionForUDFPS) { mWakeLock.setAcquired(true); } if (!messagePending) { if (DEBUG) { Log.d(TAG, "Display state changed to " + screenState + " delayed by " - + (shouldDelayTransition ? ENTER_DOZE_DELAY : 1)); + + (shouldDelayTransitionEnteringDoze ? ENTER_DOZE_DELAY : 1)); } - if (shouldDelayTransition) { + if (shouldDelayTransitionEnteringDoze) { mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY); + } else if (shouldDelayTransitionForUDFPS) { + mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState); + mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY); } else { mHandler.post(mApplyPendingScreenState); } @@ -139,6 +190,12 @@ public class DozeScreenState implements DozeMachine.Part { } private void applyPendingScreenState() { + if (mUdfpsController != null && mUdfpsController.isFingerDown()) { + mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState); + mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY); + return; + } + applyScreenState(mPendingScreenState); mPendingScreenState = Display.STATE_UNKNOWN; } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java index 455f3c0d6ac2..756adca724e9 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java @@ -41,6 +41,7 @@ import com.android.systemui.dock.DockManager; import com.android.systemui.doze.DozeMachine.State; import com.android.systemui.doze.dagger.DozeScope; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.Assert; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -92,6 +93,7 @@ public class DozeTriggers implements DozeMachine.Part { private final BroadcastDispatcher mBroadcastDispatcher; private final AuthController mAuthController; private final DelayableExecutor mMainExecutor; + private final KeyguardStateController mKeyguardStateController; private final UiEventLogger mUiEventLogger; private long mNotificationPulseTime; @@ -179,7 +181,8 @@ public class DozeTriggers implements DozeMachine.Part { DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher, SecureSettings secureSettings, AuthController authController, @Main DelayableExecutor mainExecutor, - UiEventLogger uiEventLogger) { + UiEventLogger uiEventLogger, + KeyguardStateController keyguardStateController) { mContext = context; mDozeHost = dozeHost; mConfig = config; @@ -198,6 +201,7 @@ public class DozeTriggers implements DozeMachine.Part { mAuthController = authController; mMainExecutor = mainExecutor; mUiEventLogger = uiEventLogger; + mKeyguardStateController = keyguardStateController; } @Override @@ -294,6 +298,7 @@ public class DozeTriggers implements DozeMachine.Part { proximityCheckThenCall((result) -> { if (result != null && result) { // In pocket, drop event. + mDozeLog.traceSensorEventDropped(pulseReason, "prox reporting near"); return; } if (isDoubleTap || isTap) { @@ -302,6 +307,10 @@ public class DozeTriggers implements DozeMachine.Part { } gentleWakeUp(pulseReason); } else if (isPickup) { + if (shouldDropPickupEvent()) { + mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded"); + return; + } gentleWakeUp(pulseReason); } else if (isUdfpsLongPress) { final State state = mMachine.getState(); @@ -320,7 +329,7 @@ public class DozeTriggers implements DozeMachine.Part { }, true /* alreadyPerformedProxCheck */, pulseReason); } - if (isPickup) { + if (isPickup && !shouldDropPickupEvent()) { final long timeSinceNotification = SystemClock.elapsedRealtime() - mNotificationPulseTime; final boolean withinVibrationThreshold = @@ -329,6 +338,10 @@ public class DozeTriggers implements DozeMachine.Part { } } + private boolean shouldDropPickupEvent() { + return mKeyguardStateController.isOccluded(); + } + private void gentleWakeUp(int reason) { // Log screen wake up reason (lift/pickup, tap, double-tap) Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason)) diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java index d30783c29f92..a51ec54ebcce 100644 --- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java @@ -102,7 +102,6 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer { @Override public Size reportSurfaceSize() { - mTexture.use(null /* consumer */); mSurfaceSize.set(mTexture.getTextureDimensions()); return new Size(mSurfaceSize.width(), mSurfaceSize.height()); } @@ -124,6 +123,7 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer { private final WallpaperManager mWallpaperManager; private Bitmap mBitmap; private boolean mWcgContent; + private boolean mTextureUsed; private WallpaperTexture(WallpaperManager wallpaperManager) { mWallpaperManager = wallpaperManager; @@ -141,6 +141,7 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer { mWallpaperManager.forgetLoadedWallpaper(); if (mBitmap != null) { mDimensions.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); + mTextureUsed = true; } else { Log.w(TAG, "Can't get bitmap"); } @@ -171,6 +172,9 @@ public class ImageWallpaperRenderer implements GLWallpaperRenderer { } private Rect getTextureDimensions() { + if (!mTextureUsed) { + mDimensions.set(mWallpaperManager.peekBitmapDimensions()); + } return mDimensions; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java index 2d215e0f1f62..a424674ed252 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java @@ -100,8 +100,7 @@ public class KeyguardIndicationRotateTextViewController extends */ public void updateIndication(@IndicationType int type, KeyguardIndication newIndication, boolean updateImmediately) { - if (type == INDICATION_TYPE_NOW_PLAYING - || type == INDICATION_TYPE_REVERSE_CHARGING) { + if (type == INDICATION_TYPE_REVERSE_CHARGING) { // temporarily don't show here, instead use AmbientContainer b/181049781 return; } @@ -303,7 +302,6 @@ public class KeyguardIndicationRotateTextViewController extends public static final int INDICATION_TYPE_TRUST = 6; public static final int INDICATION_TYPE_RESTING = 7; public static final int INDICATION_TYPE_USER_LOCKED = 8; - public static final int INDICATION_TYPE_NOW_PLAYING = 9; public static final int INDICATION_TYPE_REVERSE_CHARGING = 10; @IntDef({ @@ -317,7 +315,6 @@ public class KeyguardIndicationRotateTextViewController extends INDICATION_TYPE_TRUST, INDICATION_TYPE_RESTING, INDICATION_TYPE_USER_LOCKED, - INDICATION_TYPE_NOW_PLAYING, INDICATION_TYPE_REVERSE_CHARGING, }) @Retention(RetentionPolicy.SOURCE) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ee3d40edc2eb..1a8af3bb650b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -818,6 +818,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, private final KeyguardStateController mKeyguardStateController; private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy; + private boolean mWallpaperSupportsAmbientMode; /** * Injected constructor. See {@link KeyguardModule}. @@ -2089,13 +2090,14 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, int flags = 0; if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock() - || (mWakeAndUnlocking && !mPulsing) - || isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) { + || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) { flags |= WindowManagerPolicyConstants .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade() - || (mWakeAndUnlocking && mPulsing)) { + || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) { + // When the wallpaper supports ambient mode, the scrim isn't fully opaque during + // wake and unlock and we should fade in the app on top of the wallpaper flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; } if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) { @@ -2784,6 +2786,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable, mPulsing = pulsing; } + /** + * Set if the wallpaper supports ambient mode. This is used to trigger the right animation. + * In case it does support it, we have to fade in the incoming app, otherwise we'll reveal it + * with the light reveal scrim. + */ + public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) { + mWallpaperSupportsAmbientMode = supportsAmbientMode; + } + private static class StartKeyguardExitAnimParams { @WindowManager.TransitionOldType int mTransit; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index cb11454e44ee..5d37bff192eb 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -410,6 +410,12 @@ public class NavigationBar implements View.OnAttachStateChangeListener, new Handler(Looper.getMainLooper())) { @Override public void onChange(boolean selfChange, Uri uri) { + // TODO(b/198002034): Content observers currently can still be called back after being + // unregistered, and in this case we can ignore the change if the nav bar has been + // destroyed already + if (mNavigationBarView == null) { + return; + } updateAssistantEntrypoints(); } }; @@ -651,7 +657,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener, if (mIsOnDefaultDisplay) { final RotationButtonController rotationButtonController = mNavigationBarView.getRotationButtonController(); - rotationButtonController.addRotationCallback(mRotationWatcher); + rotationButtonController.setRotationCallback(mRotationWatcher); // Reset user rotation pref to match that of the WindowManager if starting in locked // mode. This will automatically happen when switching from auto-rotate to locked mode. @@ -690,6 +696,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener, @Override public void onViewDetachedFromWindow(View v) { + final RotationButtonController rotationButtonController = + mNavigationBarView.getRotationButtonController(); + rotationButtonController.setRotationCallback(null); mNavigationBarView.getBarTransitions().destroy(); mNavigationBarView.getLightTransitionsController().destroy(mContext); mOverviewProxyService.removeCallback(mOverviewProxyListener); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java index 61e803312b55..70c21e43b79a 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java @@ -101,10 +101,7 @@ import java.util.function.Consumer; public class NavigationBarView extends FrameLayout implements NavigationModeController.ModeChangedListener { final static boolean DEBUG = false; - final static String TAG = "StatusBar/NavBarView"; - - // slippery nav bar when everything is disabled, e.g. during setup - final static boolean SLIPPERY_WHEN_DISABLED = true; + final static String TAG = "NavBarView"; final static boolean ALTERNATE_CAR_MODE_UI = false; private final RegionSamplingHelper mRegionSamplingHelper; @@ -274,7 +271,7 @@ public class NavigationBarView extends FrameLayout implements }; private final Consumer<Boolean> mRotationButtonListener = (visible) -> { - if (visible) { + if (visible && mAutoHideController != null) { // If the button will actually become visible and the navbar is about to hide, // tell the statusbar to keep it around for longer mAutoHideController.touchAutoHide(); @@ -373,6 +370,12 @@ 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; } @@ -1313,6 +1316,7 @@ public class NavigationBarView extends FrameLayout implements dumpButton(pw, "back", getBackButton()); dumpButton(pw, "home", getHomeButton()); + dumpButton(pw, "handle", getHomeHandle()); dumpButton(pw, "rcnt", getRecentsButton()); dumpButton(pw, "rota", getRotateSuggestionButton()); dumpButton(pw, "a11y", getAccessibilityButton()); diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java index 649ac875b4c2..8ea9ae3c21c5 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java @@ -180,7 +180,7 @@ public class RotationButtonController { TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener); } - void addRotationCallback(Consumer<Integer> watcher) { + void setRotationCallback(Consumer<Integer> watcher) { mRotWatcherListener = watcher; } diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt index a626681c0b01..d0aa710ecea6 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt @@ -29,6 +29,7 @@ import android.util.Log import androidx.annotation.MainThread import androidx.annotation.VisibleForTesting import androidx.annotation.WorkerThread +import com.android.internal.logging.UiEventLogger import com.android.systemui.appops.AppOpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -67,6 +68,7 @@ class PrivacyDialogController( private val privacyLogger: PrivacyLogger, private val keyguardStateController: KeyguardStateController, private val appOpsController: AppOpsController, + private val uiEventLogger: UiEventLogger, @VisibleForTesting private val dialogProvider: DialogProvider ) { @@ -81,7 +83,8 @@ class PrivacyDialogController( @Main uiExecutor: Executor, privacyLogger: PrivacyLogger, keyguardStateController: KeyguardStateController, - appOpsController: AppOpsController + appOpsController: AppOpsController, + uiEventLogger: UiEventLogger ) : this( permissionManager, packageManager, @@ -93,6 +96,7 @@ class PrivacyDialogController( privacyLogger, keyguardStateController, appOpsController, + uiEventLogger, defaultDialogProvider ) @@ -105,6 +109,7 @@ class PrivacyDialogController( private val onDialogDismissed = object : PrivacyDialog.OnDialogDismissed { override fun onDialogDismissed() { privacyLogger.logPrivacyDialogDismissed() + uiEventLogger.log(PrivacyDialogEvent.PRIVACY_DIALOG_DISMISSED) dialog = null } } @@ -114,6 +119,8 @@ class PrivacyDialogController( val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS) intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName) intent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) + uiEventLogger.log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS, + userId, packageName) privacyLogger.logStartSettingsActivityFromDialog(packageName, userId) if (!keyguardStateController.isUnlocked) { // If we are locked, hide the dialog so the user can unlock @@ -155,7 +162,7 @@ class PrivacyDialogController( val items = usage.mapNotNull { val type = filterType(permGroupToPrivacyType(it.permGroupName)) val userInfo = userInfos.firstOrNull { ui -> ui.id == UserHandle.getUserId(it.uid) } - userInfo?.let { ui -> + if (userInfo != null || it.isPhoneCall) { type?.let { t -> // Only try to get the app name if we actually need it val appName = if (it.isPhoneCall) { @@ -171,10 +178,14 @@ class PrivacyDialogController( it.attribution, it.lastAccess, it.isActive, - ui.isManagedProfile, + // If there's no user info, we're in a phoneCall in secondary user + userInfo?.isManagedProfile ?: false, it.isPhoneCall ) } + } else { + // No matching user or phone call + null } } uiExecutor.execute { diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt new file mode 100644 index 000000000000..3ecc5a5e5b00 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt @@ -0,0 +1,30 @@ +/* + * 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.privacy + +import com.android.internal.logging.UiEvent +import com.android.internal.logging.UiEventLogger + +enum class PrivacyDialogEvent(private val _id: Int) : UiEventLogger.UiEventEnum { + @UiEvent(doc = "Privacy dialog is clicked by user to go to the app settings page.") + PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS(904), + + @UiEvent(doc = "Privacy dialog is dismissed by user.") + PRIVACY_DIALOG_DISMISSED(905); + + override fun getId() = _id +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java index d5349d378305..e60fb494e82b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java @@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices; import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private final UiEventLogger mUiEventLogger; private final InstanceIdSequence mInstanceIdSequence; private final CustomTileStatePersister mCustomTileStatePersister; + private final FeatureFlags mFeatureFlags; private final List<Callback> mCallbacks = new ArrayList<>(); private AutoTileManager mAutoTiles; @@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D UiEventLogger uiEventLogger, UserTracker userTracker, SecureSettings secureSettings, - CustomTileStatePersister customTileStatePersister + CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags ) { mIconController = iconController; mContext = context; @@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D mUserTracker = userTracker; mSecureSettings = secureSettings; mCustomTileStatePersister = customTileStatePersister; + mFeatureFlags = featureFlags; mainHandler.post(() -> { // This is technically a hack to avoid circular dependency of @@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) { newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode); } - final List<String> tileSpecs = loadTileSpecs(mContext, newValue); + final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags); int currentUser = mUserTracker.getUserId(); if (currentUser != mCurrentUser) { mUserContext = mUserTracker.getUserContext(); @@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D if (newTiles.isEmpty() && !tileSpecs.isEmpty()) { // If we didn't manage to create any tiles, set it to empty (default) Log.d(TAG, "No valid tiles on tuning changed. Setting to default."); - changeTiles(currentSpecs, loadTileSpecs(mContext, "")); + changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags)); } else { for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).onTilesChanged(); @@ -402,7 +406,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D private void changeTileSpecs(Predicate<List<String>> changeFunction) { final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser); - final List<String> tileSpecs = loadTileSpecs(mContext, setting); + final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags); if (changeFunction.test(tileSpecs)) { saveTilesToSettings(tileSpecs); } @@ -491,7 +495,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec()); } - protected static List<String> loadTileSpecs(Context context, String tileList) { + protected static List<String> loadTileSpecs( + Context context, String tileList, FeatureFlags featureFlags) { final Resources res = context.getResources(); if (TextUtils.isEmpty(tileList)) { @@ -524,6 +529,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D } } } + if (featureFlags.isProviderModelSettingEnabled()) { + if (!tiles.contains("internet")) { + if (tiles.contains("wifi")) { + // Replace the WiFi with Internet, and remove the Cell + tiles.set(tiles.indexOf("wifi"), "internet"); + tiles.remove("cell"); + } else if (tiles.contains("cell")) { + // Replace the Cell with Internet + tiles.set(tiles.indexOf("cell"), "internet"); + } + } else { + tiles.remove("wifi"); + tiles.remove("cell"); + } + } return tiles; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 3c2f35b954ea..f2832b3d45ff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.external.CustomTile; import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.leak.GarbageMonitor; import java.util.ArrayList; @@ -62,6 +63,7 @@ public class TileQueryHelper { private final Executor mBgExecutor; private final Context mContext; private final UserTracker mUserTracker; + private final FeatureFlags mFeatureFlags; private TileStateListener mListener; private boolean mFinished; @@ -71,12 +73,14 @@ public class TileQueryHelper { Context context, UserTracker userTracker, @Main Executor mainExecutor, - @Background Executor bgExecutor + @Background Executor bgExecutor, + FeatureFlags featureFlags ) { mContext = context; mMainExecutor = mainExecutor; mBgExecutor = bgExecutor; mUserTracker = userTracker; + mFeatureFlags = featureFlags; } public void setListener(TileStateListener listener) { @@ -117,6 +121,10 @@ public class TileQueryHelper { } final ArrayList<QSTile> tilesToAdd = new ArrayList<>(); + if (mFeatureFlags.isProviderModelSettingEnabled()) { + possibleTiles.remove("cell"); + possibleTiles.remove("wifi"); + } for (String spec : possibleTiles) { // Only add current and stock tiles that can be created from QSFactoryImpl. diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index 34f2b6331678..87edc2cf8bac 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -47,6 +47,7 @@ import javax.inject.Inject; /** Quick settings tile: Hotspot **/ public class HotspotTile extends QSTileImpl<BooleanState> { + private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot); private final HotspotController mHotspotController; @@ -98,7 +99,7 @@ public class HotspotTile extends QSTileImpl<BooleanState> { @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_TETHER_SETTINGS); + return new Intent(Settings.ACTION_WIFI_TETHER_SETTING); } @Override 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 b1db8a97b8af..08da68037c58 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 @@ -52,6 +52,7 @@ import android.widget.ProgressBar; import android.widget.Switch; import android.widget.TextView; +import androidx.annotation.MainThread; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; @@ -60,7 +61,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; -import com.android.settingslib.Utils; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; @@ -105,12 +105,10 @@ public class InternetDialog extends SystemUIDialog implements private View mDivider; private ProgressBar mProgressBar; private LinearLayout mInternetDialogLayout; - private LinearLayout mInternetListLayout; private LinearLayout mConnectedWifListLayout; - private LinearLayout mConnectedWifList; private LinearLayout mMobileNetworkLayout; - private LinearLayout mMobileNetworkList; private LinearLayout mTurnWifiOnLayout; + private LinearLayout mEthernetLayout; private TextView mWifiToggleTitleText; private LinearLayout mSeeAllLayout; private RecyclerView mWifiRecyclerView; @@ -126,7 +124,6 @@ public class InternetDialog extends SystemUIDialog implements private Button mDoneButton; private Drawable mBackgroundOn; private int mListMaxHeight; - private int mLayoutWidth; private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private boolean mCanConfigMobileData; @@ -181,8 +178,6 @@ public class InternetDialog extends SystemUIDialog implements }; mListMaxHeight = context.getResources().getDimensionPixelSize( R.dimen.internet_dialog_list_max_height); - mLayoutWidth = context.getResources().getDimensionPixelSize( - R.dimen.internet_dialog_list_max_width); mUiEventLogger = uiEventLogger; mAdapter = new InternetAdapter(mInternetDialogController); if (!aboveStatusBar) { @@ -221,13 +216,11 @@ public class InternetDialog extends SystemUIDialog implements mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle); mDivider = mDialogView.requireViewById(R.id.divider); mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress); - mInternetListLayout = mDialogView.requireViewById(R.id.internet_list); + mEthernetLayout = mDialogView.requireViewById(R.id.ethernet_layout); mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout); - mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list); mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout); mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title); mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout); - mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list); mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon); mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title); mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary); @@ -309,6 +302,7 @@ public class InternetDialog extends SystemUIDialog implements } else { mInternetDialogSubTitle.setText(getSubtitleText()); } + updateEthernet(); setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular()); if (!mCanConfigWifi) { @@ -355,6 +349,12 @@ public class InternetDialog extends SystemUIDialog implements mDoneButton.setOnClickListener(v -> dismiss()); } + @MainThread + private void updateEthernet() { + mEthernetLayout.setVisibility( + mInternetDialogController.hasEthernet() ? View.VISIBLE : View.GONE); + } + private void setMobileDataLayout(boolean isCellularNetwork) { if (mInternetDialogController.isAirplaneModeEnabled() || !mInternetDialogController.hasCarrier()) { @@ -371,38 +371,33 @@ public class InternetDialog extends SystemUIDialog implements mMobileSummaryText.setVisibility(View.GONE); } mSignalIcon.setImageDrawable(getSignalStrengthDrawable()); - if (mInternetDialogController.isNightMode()) { - int titleColor = isCellularNetwork ? mContext.getColor( - R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor( - mContext, android.R.attr.textColorPrimary); - int summaryColor = isCellularNetwork ? mContext.getColor( - R.color.connected_network_secondary_color) : Utils.getColorAttrDefaultColor( - mContext, android.R.attr.textColorSecondary); - - mMobileTitleText.setTextColor(titleColor); - mMobileSummaryText.setTextColor(summaryColor); - } + mMobileTitleText.setTextAppearance(isCellularNetwork + ? R.style.TextAppearance_InternetDialog_Active + : R.style.TextAppearance_InternetDialog); + mMobileSummaryText.setTextAppearance(isCellularNetwork + ? R.style.TextAppearance_InternetDialog_Secondary_Active + : R.style.TextAppearance_InternetDialog_Secondary); mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null); mMobileDataToggle.setVisibility(mCanConfigMobileData ? View.VISIBLE : View.INVISIBLE); } } + @MainThread private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) { mWiFiToggle.setChecked(isWifiEnabled); - if (isDeviceLocked && mInternetDialogController.isNightMode()) { - int titleColor = mConnectedWifiEntry != null ? mContext.getColor( - R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor( - mContext, android.R.attr.textColorPrimary); - mWifiToggleTitleText.setTextColor(titleColor); + if (isDeviceLocked) { + mWifiToggleTitleText.setTextAppearance((mConnectedWifiEntry != null) + ? R.style.TextAppearance_InternetDialog_Active + : R.style.TextAppearance_InternetDialog); } mTurnWifiOnLayout.setBackground( (isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null); } + @MainThread private void updateConnectedWifi(boolean isWifiEnabled, boolean isDeviceLocked) { if (!isWifiEnabled || mConnectedWifiEntry == null || isDeviceLocked) { - mConnectedWifListLayout.setBackground(null); mConnectedWifListLayout.setVisibility(View.GONE); return; } @@ -411,15 +406,8 @@ public class InternetDialog extends SystemUIDialog implements mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false)); mConnectedWifiIcon.setImageDrawable( mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry)); - if (mInternetDialogController.isNightMode()) { - mConnectedWifiTitleText.setTextColor( - mContext.getColor(R.color.connected_network_primary_color)); - mConnectedWifiSummaryText.setTextColor( - mContext.getColor(R.color.connected_network_secondary_color)); - } mWifiSettingsIcon.setColorFilter( mContext.getColor(R.color.connected_network_primary_color)); - mConnectedWifListLayout.setBackground(mBackgroundOn); } void onClickConnectedWifi() { @@ -528,11 +516,18 @@ public class InternetDialog extends SystemUIDialog implements } @Override + @WorkerThread public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) { mHandler.post(() -> updateDialog()); } @Override + @WorkerThread + public void onLost(Network network) { + mHandler.post(() -> updateDialog()); + } + + @Override public void onSubscriptionsChanged(int defaultDataSubId) { mDefaultDataSubId = defaultDataSubId; mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); 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 70f52ad5432d..95d3915eb64d 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 @@ -23,7 +23,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Configuration; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; @@ -31,7 +30,6 @@ import android.graphics.drawable.LayerDrawable; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.os.Handler; import android.provider.Settings; @@ -49,6 +47,7 @@ import android.util.Log; import android.view.Gravity; import android.widget.Toast; +import androidx.annotation.MainThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; @@ -58,9 +57,11 @@ import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.settingslib.DeviceInfoUtils; +import com.android.settingslib.SignalIcon; import com.android.settingslib.Utils; import com.android.settingslib.graph.SignalDrawable; import com.android.settingslib.mobile.MobileMappings; +import com.android.settingslib.mobile.TelephonyIcons; import com.android.settingslib.net.SignalStrengthUtil; import com.android.settingslib.wifi.WifiUtils; import com.android.systemui.R; @@ -131,6 +132,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private GlobalSettings mGlobalSettings; private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + private ConnectivityManager.NetworkCallback mConnectivityManagerNetworkCallback; @VisibleForTesting protected ActivityStarter mActivityStarter; @@ -144,6 +146,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, protected boolean mCanConfigWifi; @VisibleForTesting protected KeyguardStateController mKeyguardStateController; + @VisibleForTesting + protected boolean mHasEthernet = false; private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = new KeyguardUpdateMonitorCallback() { @@ -191,6 +195,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mAccessPointController = accessPointController; mConfig = MobileMappings.Config.readConfig(mContext); mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext); + mConnectivityManagerNetworkCallback = new DataConnectivityListener(); } void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) { @@ -214,9 +219,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mInternetTelephonyCallback = new InternetTelephonyCallback(); mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback); // Listen the connectivity changes - mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(), new DataConnectivityListener(), mHandler); + mConnectivityManager.registerDefaultNetworkCallback(mConnectivityManagerNetworkCallback); mCanConfigWifi = canConfigWifi; scanWifiAccessPoints(); } @@ -231,6 +234,7 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, mOnSubscriptionsChangedListener); mAccessPointController.removeAccessPointCallback(this); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); + mConnectivityManager.unregisterNetworkCallback(mConnectivityManagerNetworkCallback); } @VisibleForTesting @@ -349,11 +353,6 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, return drawable; } - boolean isNightMode() { - return (mContext.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; - } - Drawable getSignalStrengthDrawable() { Drawable drawable = mContext.getDrawable( R.drawable.ic_signal_strength_zero_bar_no_internet); @@ -534,6 +533,14 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } int resId = mapIconSets(config).get(iconKey).dataContentDescription; + final MergedCarrierEntry mergedCarrierEntry = + mAccessPointController.getMergedCarrierEntry(); + if (mergedCarrierEntry != null && mergedCarrierEntry.isDefaultNetwork()) { + SignalIcon.MobileIconGroup carrierMergedWifiIconGroup = + TelephonyIcons.CARRIER_MERGED_WIFI; + resId = carrierMergedWifiIconGroup.dataContentDescription; + } + return resId != 0 ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; } @@ -790,6 +797,9 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, } int count = MAX_WIFI_ENTRY_COUNT; + if (mHasEthernet) { + count -= 1; + } if (hasCarrier()) { count -= 1; } @@ -860,23 +870,32 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, @Override @WorkerThread public void onCapabilitiesChanged(@NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities) { - if (mCanConfigWifi) { - for (int transport : networkCapabilities.getTransportTypes()) { - if (transport == NetworkCapabilities.TRANSPORT_WIFI) { - scanWifiAccessPoints(); - break; - } - } - } - final Network activeNetwork = mConnectivityManager.getActiveNetwork(); - if (activeNetwork != null && activeNetwork.equals(network)) { - // update UI - mCallback.onCapabilitiesChanged(network, networkCapabilities); + @NonNull NetworkCapabilities capabilities) { + mHasEthernet = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET); + if (mCanConfigWifi && (mHasEthernet || capabilities.hasTransport( + NetworkCapabilities.TRANSPORT_WIFI))) { + scanWifiAccessPoints(); } + // update UI + mCallback.onCapabilitiesChanged(network, capabilities); + } + + @Override + @WorkerThread + public void onLost(@NonNull Network network) { + mHasEthernet = false; + mCallback.onLost(network); } } + /** + * Return {@code true} If the Ethernet exists + */ + @MainThread + public boolean hasEthernet() { + return mHasEthernet; + } + private final BroadcastReceiver mConnectionStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -924,6 +943,8 @@ public class InternetDialogController implements WifiEntry.DisconnectCallback, void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities); + void onLost(@NonNull Network network); + void onSubscriptionsChanged(int defaultDataSubId); void onServiceStateChanged(ServiceState serviceState); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 445715e138ab..17bcfe73ccd9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -66,6 +66,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.ViewClippingUtil; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.settingslib.Utils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; @@ -455,7 +456,8 @@ public class KeyguardIndicationController { new KeyguardIndication.Builder() .setMessage(mContext.getResources().getString( com.android.internal.R.string.global_action_logout)) - .setTextColor(mInitialTextColorState) + .setTextColor(Utils.getColorAttr( + mContext, com.android.internal.R.attr.textColorOnAccent)) .setBackground(mContext.getDrawable( com.android.systemui.R.drawable.logout_button_background)) .setClickListener((view) -> { @@ -798,7 +800,9 @@ public class KeyguardIndicationController { * Show message on the keyguard for how the user can unlock/enter their device. */ public void showActionToUnlock() { - if (mDozing) { + if (mDozing + && !mKeyguardUpdateMonitor.getUserCanSkipBouncer( + KeyguardUpdateMonitor.getCurrentUser())) { return; } @@ -809,7 +813,7 @@ public class KeyguardIndicationController { String message = mContext.getString(R.string.keyguard_retry); mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); } - } else if (mKeyguardUpdateMonitor.isScreenOn()) { + } else { showTransientIndication(mContext.getString(R.string.keyguard_unlock), false /* isError */, true /* hideOnScreenOff */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index a771274e3433..0134b9f9c618 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -615,6 +615,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll); mGroupMembershipManager = groupMembershipManager; mGroupExpansionManager = groupExpansionManager; + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); } void initializeForegroundServiceSection(ForegroundServiceDungeonView fgsSectionView) { 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 6e201048abdb..2c76cfeff733 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -116,7 +116,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp /** * Mode in which fingerprint unlocks the device or passive auth (ie face auth) unlocks the - * device while being requested when keyguard is occluded. + * device while being requested when keyguard is occluded or showing. */ public static final int MODE_UNLOCK_COLLAPSING = 5; @@ -425,6 +425,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (!wasDeviceInteractive) { mPendingShowBouncer = true; } else { + mShadeController.animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_NONE, + true /* force */, + false /* delayed */, + BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); mPendingShowBouncer = false; mKeyguardViewController.notifyKeyguardAuthenticated( false /* strongAuth */); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java index 36f6c4fd57a2..e67c6ac3a7c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java @@ -268,13 +268,6 @@ public class DozeParameters implements TunerService.Tunable, } /** - * Whether the brightness sensor uses the proximity sensor. - */ - public boolean brightnessUsesProx() { - return mResources.getBoolean(R.bool.doze_brightness_uses_prox); - } - - /** * Callback to listen for DozeParameter changes. */ public void addCallback(Callback callback) { @@ -298,6 +291,7 @@ public class DozeParameters implements TunerService.Tunable, @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + pw.print("getAlwaysOn(): "); pw.println(getAlwaysOn()); pw.print("getDisplayStateSupported(): "); pw.println(getDisplayStateSupported()); pw.print("getPulseDuration(): "); pw.println(getPulseDuration()); pw.print("getPulseInDuration(): "); pw.println(getPulseInDuration()); @@ -310,7 +304,6 @@ public class DozeParameters implements TunerService.Tunable, pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); pw.print("getSelectivelyRegisterSensorsUsingProx(): "); pw.println(getSelectivelyRegisterSensorsUsingProx()); - pw.print("brightnessUsesProx(): "); pw.println(brightnessUsesProx()); } interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java index b2cf72aca864..21c3e5e0a8d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java @@ -116,11 +116,18 @@ public class DozeScrimController implements StateListener { if (!mDozing || mPulseCallback != null) { if (DEBUG) { - Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? " + Log.d(TAG, "Pulse suppressed. Dozing: " + mDozeParameters + " had callback? " + (mPulseCallback != null)); } // Pulse suppressed. callback.onPulseFinished(); + if (!mDozing) { + mDozeLog.tracePulseDropped("device isn't dozing"); + } else { + mDozeLog.tracePulseDropped("already has pulse callback mPulseCallback=" + + mPulseCallback); + } + return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java index f1cde8a9be7a..a5b5f1cbf1e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java @@ -28,7 +28,10 @@ import android.util.AttributeSet; import android.view.View; import android.widget.TextView; +import androidx.annotation.StyleRes; + import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.keyguard.KeyguardIndication; @@ -39,6 +42,12 @@ import java.util.LinkedList; */ public class KeyguardIndicationTextView extends TextView { private static final long MSG_MIN_DURATION_MILLIS_DEFAULT = 1500; + + @StyleRes + private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea; + @StyleRes + private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button; + private long mNextAnimationTime = 0; private boolean mAnimationsEnabled = true; private LinkedList<CharSequence> mMessages = new LinkedList<>(); @@ -136,6 +145,14 @@ public class KeyguardIndicationTextView extends TextView { public void onAnimationEnd(Animator animator) { KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (info != null) { + // First, update the style. + // If a background is set on the text, we don't want shadow on the text + if (info.getBackground() != null) { + setTextAppearance(sButtonStyleId); + } else { + setTextAppearance(sStyleId); + } + setBackground(info.getBackground()); setTextColor(info.getTextColor()); setOnClickListener(info.getClickListener()); setClickable(info.getClickListener() != null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index baef809e043e..733f83c60e4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -853,13 +853,13 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header); mBigClockContainer = mView.findViewById(R.id.big_clock_container); - UserAvatarView userAvatarView = null; + FrameLayout userAvatarContainer = null; KeyguardUserSwitcherView keyguardUserSwitcherView = null; if (mKeyguardUserSwitcherEnabled && mUserManager.isUserSwitcherEnabled()) { if (mKeyguardQsUserSwitchEnabled) { ViewStub stub = mView.findViewById(R.id.keyguard_qs_user_switch_stub); - userAvatarView = (UserAvatarView) stub.inflate(); + userAvatarContainer = (FrameLayout) stub.inflate(); } else { ViewStub stub = mView.findViewById(R.id.keyguard_user_switcher_stub); keyguardUserSwitcherView = (KeyguardUserSwitcherView) stub.inflate(); @@ -868,7 +868,7 @@ public class NotificationPanelViewController extends PanelViewController { updateViewControllers( mView.findViewById(R.id.keyguard_status_view), - userAvatarView, + userAvatarContainer, mKeyguardStatusBar, keyguardUserSwitcherView); mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent); @@ -960,7 +960,7 @@ public class NotificationPanelViewController extends PanelViewController { } private void updateViewControllers(KeyguardStatusView keyguardStatusView, - UserAvatarView userAvatarView, + FrameLayout userAvatarView, KeyguardStatusBarView keyguardStatusBarView, KeyguardUserSwitcherView keyguardUserSwitcherView) { // Re-associate the KeyguardStatusViewController @@ -1112,7 +1112,7 @@ public class NotificationPanelViewController extends PanelViewController { !mKeyguardQsUserSwitchEnabled && mKeyguardUserSwitcherEnabled && isUserSwitcherEnabled; - UserAvatarView userAvatarView = (UserAvatarView) reInflateStub( + FrameLayout userAvatarView = (FrameLayout) reInflateStub( R.id.keyguard_qs_user_switch_view /* viewId */, R.id.keyguard_qs_user_switch_stub /* stubId */, R.layout.keyguard_qs_user_switch /* layoutId */, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index d7a359e9b4d4..65072f4d67b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -592,6 +592,7 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); + mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode); } }; @@ -3924,7 +3925,8 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public void onDozeAmountChanged(float linear, float eased) { if (mFeatureFlags.useNewLockscreenAnimations() - && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) { + && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal) + && !mBiometricUnlockController.isWakeAndUnlock()) { mLightRevealScrim.setRevealAmount(1f - linear); } } 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 3653b95351b0..720690fde9e2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -194,6 +194,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastGesturalNav; private boolean mLastIsDocked; private boolean mLastPulsing; + private boolean mLastAnimatedToSleep; private int mLastBiometricMode; private boolean mQsExpanded; private boolean mAnimatedToSleep; @@ -992,6 +993,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mLastBiometricMode = mBiometricUnlockController.getMode(); mLastGesturalNav = mGesturalNav; mLastIsDocked = mIsDocked; + mLastAnimatedToSleep = mAnimatedToSleep; mStatusBar.onKeyguardViewManagerStatesUpdated(); } @@ -1035,7 +1037,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING; boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing || mLastPulsing && !mLastIsDocked) && mLastGesturalNav; - return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing + return (!mLastAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mLastBouncerShowing || mLastRemoteInputActive || keyguardWithGestureNav || mLastGlobalActionsVisible); } 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 f8120a8a7029..143aaba648da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt @@ -8,13 +8,13 @@ import android.content.res.Configuration import android.database.ContentObserver import android.os.Handler import android.provider.Settings -import com.android.systemui.statusbar.StatusBarState import android.view.View import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.KeyguardViewMediator import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.statusbar.LightRevealScrim +import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.StatusBarStateControllerImpl import com.android.systemui.statusbar.notification.AnimatableProperty import com.android.systemui.statusbar.notification.PropertyAnimator @@ -61,6 +61,7 @@ class UnlockedScreenOffAnimationController @Inject constructor( private var shouldAnimateInKeyguard = false private var lightRevealAnimationPlaying = false private var aodUiAnimationPlaying = false + private var callbacks = HashSet<Callback>() /** * The result of our decision whether to play the screen off animation in @@ -72,11 +73,17 @@ class UnlockedScreenOffAnimationController @Inject constructor( private val lightRevealAnimator = ValueAnimator.ofFloat(1f, 0f).apply { duration = LIGHT_REVEAL_ANIMATION_DURATION interpolator = Interpolators.LINEAR - addUpdateListener { lightRevealScrim.revealAmount = it.animatedValue as Float } + addUpdateListener { + lightRevealScrim.revealAmount = it.animatedValue as Float + sendUnlockedScreenOffProgressUpdate( + 1f - (it.animatedFraction as Float), + 1f - (it.animatedValue as Float)) + } addListener(object : AnimatorListenerAdapter() { override fun onAnimationCancel(animation: Animator?) { lightRevealScrim.revealAmount = 1f lightRevealAnimationPlaying = false + sendUnlockedScreenOffProgressUpdate(0f, 0f) } override fun onAnimationEnd(animation: Animator?) { @@ -243,7 +250,21 @@ class UnlockedScreenOffAnimationController @Inject constructor( return true } - /** + fun addCallback(callback: Callback) { + callbacks.add(callback) + } + + fun removeCallback(callback: Callback) { + callbacks.remove(callback) + } + + fun sendUnlockedScreenOffProgressUpdate(linear: Float, eased: Float) { + callbacks.forEach { + it.onUnlockedScreenOffProgressUpdate(linear, eased) + } + } + +/** * Whether we're doing the light reveal animation or we're done with that and animating in the * AOD UI. */ @@ -262,4 +283,8 @@ class UnlockedScreenOffAnimationController @Inject constructor( fun isScreenOffLightRevealAnimationPlaying(): Boolean { return lightRevealAnimationPlaying } + + interface Callback { + fun onUnlockedScreenOffProgressUpdate(linear: Float, eased: Float) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index a0edc7c494bc..1e5251196379 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -149,7 +149,7 @@ public class BrightnessMirrorController private void reinflate() { int index = mStatusBarWindow.indexOfChild(mBrightnessMirror); mStatusBarWindow.removeView(mBrightnessMirror); - mBrightnessMirror = (FrameLayout) LayoutInflater.from(mBrightnessMirror.getContext()) + mBrightnessMirror = (FrameLayout) LayoutInflater.from(mStatusBarWindow.getContext()) .inflate(R.layout.brightness_mirror_container, mStatusBarWindow, false); mToggleSliderController = setMirrorLayout(); mStatusBarWindow.addView(mBrightnessMirror, index); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index 5e70d0dbc418..d838a05135e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -27,6 +27,7 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardVisibilityHelper; @@ -56,7 +57,7 @@ import javax.inject.Provider; * Manages the user switch on the Keyguard that is used for opening the QS user panel. */ @KeyguardUserSwitcherScope -public class KeyguardQsUserSwitchController extends ViewController<UserAvatarView> { +public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> { private static final String TAG = "KeyguardQsUserSwitchController"; private static final boolean DEBUG = KeyguardConstants.DEBUG; @@ -76,6 +77,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie private final KeyguardVisibilityHelper mKeyguardVisibilityHelper; private final KeyguardUserDetailAdapter mUserDetailAdapter; private NotificationPanelViewController mNotificationPanelViewController; + private UserAvatarView mUserAvatarView; UserSwitcherController.UserRecord mCurrentUser; // State info for the user switch and keyguard @@ -111,7 +113,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie @Inject public KeyguardQsUserSwitchController( - UserAvatarView view, + FrameLayout view, Context context, @Main Resources resources, ScreenLifecycle screenLifecycle, @@ -143,6 +145,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie protected void onInit() { super.onInit(); if (DEBUG) Log.d(TAG, "onInit"); + mUserAvatarView = mView.findViewById(R.id.kg_multi_user_avatar); mAdapter = new UserSwitcherController.BaseUserAdapter(mUserSwitcherController) { @Override public View getView(int position, View convertView, ViewGroup parent) { @@ -150,11 +153,10 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie } }; - mView.setOnClickListener(v -> { + mUserAvatarView.setOnClickListener(v -> { if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return; } - if (isListAnimating()) { return; } @@ -163,7 +165,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie openQsUserPanel(); }); - mView.setAccessibilityDelegate(new View.AccessibilityDelegate() { + mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() { public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); info.addAction(new AccessibilityNodeInfo.AccessibilityAction( @@ -237,12 +239,12 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie R.string.accessibility_multi_user_switch_switcher); } - if (!TextUtils.equals(mView.getContentDescription(), contentDescription)) { - mView.setContentDescription(contentDescription); + if (!TextUtils.equals(mUserAvatarView.getContentDescription(), contentDescription)) { + mUserAvatarView.setContentDescription(contentDescription); } int userId = mCurrentUser != null ? mCurrentUser.resolveId() : UserHandle.USER_NULL; - mView.setDrawableWithBadge(getCurrentUserIcon().mutate(), userId); + mUserAvatarView.setDrawableWithBadge(getCurrentUserIcon().mutate(), userId); } Drawable getCurrentUserIcon() { @@ -269,7 +271,7 @@ public class KeyguardQsUserSwitchController extends ViewController<UserAvatarVie * Get the height of the keyguard user switcher view when closed. */ public int getUserIconHeight() { - return mView.getHeight(); + return mUserAvatarView.getHeight(); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java index 20b66f03192e..cd8894cae684 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java @@ -103,7 +103,7 @@ public class KeyguardUserSwitcherListView extends AlphaOptimizedLinearLayout { } } - if (animate) { + if (animate && userItemViews.length > 1) { // AnimationUtils will immediately hide/show the first item in the array. Since the // first view is the current user, we want to manage its visibility separately. // Set first item to null so AnimationUtils ignores it. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java index 22fd93ed10ed..2d47c8f0b577 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java @@ -71,7 +71,11 @@ public class NextAlarmControllerImpl extends BroadcastReceiver if (mNextAlarm != null) { pw.println(new Date(mNextAlarm.getTriggerTime())); pw.print(" PendingIntentPkg="); - pw.println(mNextAlarm.getShowIntent().getCreatorPackage()); + if (mNextAlarm.getShowIntent() != null) { + pw.println(mNextAlarm.getShowIntent().getCreatorPackage()); + } else { + pw.println("showIntent=null"); + } } else { pw.println("null"); } diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java index 2b4b49b82df1..d44fb76f306e 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletActivity.java @@ -220,6 +220,12 @@ public class WalletActivity extends LifecycleActivity implements } @Override + protected void onStop() { + super.onStop(); + finish(); + } + + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.wallet_activity_options_menu, menu); return super.onCreateOptionsMenu(menu); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt index 8f5eefcff186..f2f0029708ed 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt @@ -19,16 +19,23 @@ package com.android.systemui.biometrics import android.graphics.PointF import android.hardware.biometrics.BiometricSourceType import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.statusbar.LightRevealScrim import com.android.systemui.statusbar.NotificationShadeWindowController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.phone.BiometricUnlockController import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.KeyguardStateController +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -54,11 +61,15 @@ class AuthRippleControllerTest : SysuiTestCase() { @Mock private lateinit var configurationController: ConfigurationController @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor @Mock private lateinit var authController: AuthController + @Mock private lateinit var keyguardStateController: KeyguardStateController + @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var bypassController: KeyguardBypassController @Mock private lateinit var biometricUnlockController: BiometricUnlockController @Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController> @Mock private lateinit var udfpsController: UdfpsController + @Mock private lateinit var statusBarStateController: StatusBarStateController + @Mock private lateinit var lightRevealScrim: LightRevealScrim @Before fun setUp() { @@ -71,14 +82,18 @@ class AuthRippleControllerTest : SysuiTestCase() { authController, configurationController, keyguardUpdateMonitor, + keyguardStateController, + wakefulnessLifecycle, commandRegistry, notificationShadeWindowController, bypassController, biometricUnlockController, udfpsControllerProvider, + statusBarStateController, rippleView ) controller.init() + `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim) } @Test @@ -100,7 +115,7 @@ class AuthRippleControllerTest : SysuiTestCase() { // THEN update sensor location and show ripple verify(rippleView).setSensorLocation(fpsLocation) - verify(rippleView).startUnlockedRipple(any(), any()) + verify(rippleView).startUnlockedRipple(any()) } @Test @@ -121,7 +136,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple - verify(rippleView, never()).startUnlockedRipple(any(), any()) + verify(rippleView, never()).startUnlockedRipple(any()) } @Test @@ -142,7 +157,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple - verify(rippleView, never()).startUnlockedRipple(any(), any()) + verify(rippleView, never()).startUnlockedRipple(any()) } @Test @@ -166,7 +181,7 @@ class AuthRippleControllerTest : SysuiTestCase() { // THEN show ripple verify(rippleView).setSensorLocation(faceLocation) - verify(rippleView).startUnlockedRipple(any(), any()) + verify(rippleView).startUnlockedRipple(any()) } @Test @@ -186,7 +201,7 @@ class AuthRippleControllerTest : SysuiTestCase() { false /* isStrongBiometric */) // THEN no ripple - verify(rippleView, never()).startUnlockedRipple(any(), any()) + verify(rippleView, never()).startUnlockedRipple(any()) } @Test @@ -201,7 +216,7 @@ class AuthRippleControllerTest : SysuiTestCase() { 0 /* userId */, BiometricSourceType.FACE /* type */, false /* isStrongBiometric */) - verify(rippleView, never()).startUnlockedRipple(any(), any()) + verify(rippleView, never()).startUnlockedRipple(any()) } @Test @@ -216,7 +231,39 @@ class AuthRippleControllerTest : SysuiTestCase() { 0 /* userId */, BiometricSourceType.FINGERPRINT /* type */, false /* isStrongBiometric */) - verify(rippleView, never()).startUnlockedRipple(any(), any()) + verify(rippleView, never()).startUnlockedRipple(any()) + } + + @Test + fun registersAndDeregisters() { + controller.onViewAttached() + val captor = ArgumentCaptor + .forClass(KeyguardStateController.Callback::class.java) + verify(keyguardStateController).addCallback(captor.capture()) + val captor2 = ArgumentCaptor + .forClass(WakefulnessLifecycle.Observer::class.java) + verify(wakefulnessLifecycle).addObserver(captor2.capture()) + controller.onViewDetached() + verify(keyguardStateController).removeCallback(any()) + verify(wakefulnessLifecycle).removeObserver(any()) + } + + @Test + @RunWithLooper(setAsMainLooper = true) + fun testAnimatorRunWhenWakeAndUnlock() { + val fpsLocation = PointF(5f, 5f) + `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation) + controller.onViewAttached() + `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true) + `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true) + + controller.showRipple(BiometricSourceType.FINGERPRINT) + assertTrue("reveal didn't start on keyguardFadingAway", + controller.startLightRevealScrimOnKeyguardFadingAway) + `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true) + controller.onKeyguardFadingAwayChanged() + assertFalse("reveal triggers multiple times", + controller.startLightRevealScrimOnKeyguardFadingAway) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 4dbfe0881b31..04ebee8913c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -57,7 +57,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; -import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -65,6 +64,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.Execution; @@ -123,8 +123,6 @@ public class UdfpsControllerTest extends SysuiTestCase { @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @Mock - private KeyguardViewMediator mKeyguardViewMediator; - @Mock private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback; @Mock private FalsingManager mFalsingManager; @@ -152,6 +150,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private ConfigurationController mConfigurationController; @Mock private SystemClock mSystemClock; + @Mock + private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; private FakeExecutor mFgExecutor; @@ -191,6 +191,7 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mLayoutInflater.inflate(R.layout.udfps_keyguard_view, null)) .thenReturn(mKeyguardView); // for showOverlay REASON_AUTH_FPM_KEYGUARD when(mEnrollView.getContext()).thenReturn(mContext); + when(mKeyguardStateController.isOccluded()).thenReturn(false); final List<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); final List<ComponentInfoInternal> componentInfo = new ArrayList<>(); @@ -221,7 +222,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mStatusBarKeyguardViewManager, mDumpManager, mKeyguardUpdateMonitor, - mKeyguardViewMediator, mFalsingManager, mPowerManager, mAccessibilityManager, @@ -235,7 +235,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mDisplayManager, mHandler, mConfigurationController, - mSystemClock); + mSystemClock, + mUnlockedScreenOffAnimationController); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java index 897ac270428f..4b35de15147b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.LockscreenShadeTransitionController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -89,6 +90,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { @Mock private ConfigurationController mConfigurationController; @Mock + private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; + @Mock private UdfpsController mUdfpsController; private FakeSystemClock mSystemClock = new FakeSystemClock(); @@ -121,13 +124,12 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase { mStatusBar, mStatusBarKeyguardViewManager, mKeyguardUpdateMonitor, - mExecutor, mDumpManager, - mKeyguardViewMediator, mLockscreenShadeTransitionController, mConfigurationController, mSystemClock, mKeyguardStateController, + mUnlockedScreenOffAnimationController, mUdfpsController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java index a32cb9b6baa9..d6226aa53f67 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java @@ -43,7 +43,6 @@ public class DozeConfigurationUtil { when(params.singleTapUsesProx()).thenReturn(true); when(params.longPressUsesProx()).thenReturn(true); when(params.getQuickPickupAodDuration()).thenReturn(500); - when(params.brightnessUsesProx()).thenReturn(true); doneHolder[0] = true; return params; diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java index deb7d31d87a3..e0520b406a0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java @@ -18,6 +18,7 @@ package com.android.systemui.doze; import static com.android.systemui.doze.DozeMachine.State.DOZE; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; +import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING; import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE; @@ -43,7 +44,6 @@ import android.os.PowerManager; import android.os.UserHandle; import android.provider.Settings; import android.testing.AndroidTestingRunner; -import android.view.Display; import androidx.test.filters.SmallTest; @@ -114,8 +114,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */, mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters, mDockManager); - - mScreen.onScreenState(Display.STATE_ON); } @Test @@ -127,18 +125,9 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test - public void testAod_usesLightSensor() { - mScreen.onScreenState(Display.STATE_DOZE); - waitForSensorManager(); - - mSensor.sendSensorEvent(3); - - assertEquals(3, mServiceFake.screenBrightness); - } - - @Test public void testAod_usesDebugValue() throws Exception { - mScreen.onScreenState(Display.STATE_DOZE); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); waitForSensorManager(); Intent intent = new Intent(DozeScreenBrightness.ACTION_AOD_BRIGHTNESS); @@ -161,34 +150,25 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test - public void testAodDocked_doNotSelectivelyUseProx_usesLightSensor() { - // GIVEN the device doesn't need to selectively register for prox sensors and - // brightness sensor uses prox - when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(false); - when(mDozeParameters.brightnessUsesProx()).thenReturn(true); - + public void doze_doesNotUseLightSensor() { // GIVEN the device is docked and the display state changes to ON - when(mDockManager.isDocked()).thenReturn(true); - mScreen.onScreenState(Display.STATE_ON); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE); waitForSensorManager(); // WHEN new sensor event sent mSensor.sendSensorEvent(3); - // THEN brightness is updated - assertEquals(3, mServiceFake.screenBrightness); + // THEN brightness is NOT changed, it's set to the default brightness + assertNotSame(3, mServiceFake.screenBrightness); + assertEquals(DEFAULT_BRIGHTNESS, mServiceFake.screenBrightness); } @Test - public void testAodDocked_brightnessDoesNotUseProx_usesLightSensor() { - // GIVEN the device doesn't need to selectively register for prox sensors but - // the brightness sensor doesn't use prox - when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true); - when(mDozeParameters.brightnessUsesProx()).thenReturn(false); - + public void aod_usesLightSensor() { // GIVEN the device is docked and the display state changes to ON - when(mDockManager.isDocked()).thenReturn(true); - mScreen.onScreenState(Display.STATE_ON); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); waitForSensorManager(); // WHEN new sensor event sent @@ -198,34 +178,25 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { assertEquals(3, mServiceFake.screenBrightness); } - @Test - public void testAodDocked_noProx_brightnessUsesProx_doNotUseLightSensor() { - final int startBrightness = mServiceFake.screenBrightness; - - // GIVEN the device needs to selectively register for prox sensors and - // the brightness sensor uses prox - when(mDozeParameters.getSelectivelyRegisterSensorsUsingProx()).thenReturn(true); - when(mDozeParameters.brightnessUsesProx()).thenReturn(true); - - // GIVEN the device is docked and the display state is on - when(mDockManager.isDocked()).thenReturn(true); - mScreen.onScreenState(Display.STATE_ON); + public void docked_usesLightSensor() { + // GIVEN the device is docked and the display state changes to ON + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + mScreen.transitionTo(DOZE_AOD, DOZE_AOD_DOCKED); waitForSensorManager(); // WHEN new sensor event sent mSensor.sendSensorEvent(3); - // THEN brightness is NOT changed - assertNotSame(3, mServiceFake.screenBrightness); - assertEquals(startBrightness, mServiceFake.screenBrightness); + // THEN brightness is updated + assertEquals(3, mServiceFake.screenBrightness); } @Test public void testPausingAod_doesNotResetBrightness() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); waitForSensorManager(); mSensor.sendSensorEvent(1); @@ -266,18 +237,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { } @Test - public void testOnScreenStateSetBeforeTransition_stillRegistersSensor() { - mScreen.transitionTo(UNINITIALIZED, INITIALIZED); - mScreen.onScreenState(Display.STATE_DOZE); - mScreen.transitionTo(INITIALIZED, DOZE_AOD); - waitForSensorManager(); - - mSensor.sendSensorEvent(1); - - assertEquals(1, mServiceFake.screenBrightness); - } - - @Test public void testNullSensor() throws Exception { mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager, Optional.empty() /* sensor */, mDozeHost, null /* handler */, @@ -287,15 +246,12 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { mScreen.transitionTo(INITIALIZED, DOZE_AOD); mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING); mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED); - mScreen.onScreenState(Display.STATE_DOZE); - mScreen.onScreenState(Display.STATE_OFF); } @Test public void testNoBrightnessDeliveredAfterFinish() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); mScreen.transitionTo(DOZE_AOD, FINISH); waitForSensorManager(); @@ -308,7 +264,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void testNonPositiveBrightness_keepsPreviousBrightnessAndScrim() { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); waitForSensorManager(); mSensor.sendSensorEvent(1); @@ -322,7 +277,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void pausingAod_unblanksAfterSensor() { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); waitForSensorManager(); mSensor.sendSensorEvent(2); @@ -334,7 +288,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { reset(mDozeHost); mScreen.transitionTo(DOZE_AOD_PAUSED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); waitForSensorManager(); mSensor.sendSensorEvent(2); verify(mDozeHost).setAodDimmingScrim(eq(0f)); @@ -344,7 +297,6 @@ public class DozeScreenBrightnessTest extends SysuiTestCase { public void pausingAod_unblanksIfSensorWasAlwaysReady() throws Exception { mScreen.transitionTo(UNINITIALIZED, INITIALIZED); mScreen.transitionTo(INITIALIZED, DOZE_AOD); - mScreen.onScreenState(Display.STATE_DOZE); waitForSensorManager(); mSensor.sendSensorEvent(2); diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java index 41d7fd64fe7a..150ab7700e4b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java @@ -21,6 +21,7 @@ import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED; import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING; +import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE; import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING; import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE; import static com.android.systemui.doze.DozeMachine.State.FINISH; @@ -34,6 +35,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -45,6 +47,8 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; +import com.android.systemui.biometrics.UdfpsController; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.util.wakelock.WakeLockFake; import com.android.systemui.utils.os.FakeHandler; @@ -56,6 +60,8 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import javax.inject.Provider; + @RunWith(AndroidJUnit4.class) @SmallTest public class DozeScreenStateTest extends SysuiTestCase { @@ -68,17 +74,29 @@ public class DozeScreenStateTest extends SysuiTestCase { private DozeParameters mDozeParameters; private WakeLockFake mWakeLock; private DozeScreenState mScreen; + @Mock + private Provider<UdfpsController> mUdfpsControllerProvider; + @Mock + private AuthController mAuthController; + @Mock + private UdfpsController mUdfpsController; + @Mock + private DozeLog mDozeLog; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true); when(mDozeParameters.getAlwaysOn()).thenReturn(true); + when(mUdfpsControllerProvider.get()).thenReturn(mUdfpsController); + when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true); + when(mUdfpsController.isFingerDown()).thenReturn(false); + mServiceFake = new DozeServiceFake(); mHandlerFake = new FakeHandler(Looper.getMainLooper()); mWakeLock = new WakeLockFake(); mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeHost, mDozeParameters, - mWakeLock); + mWakeLock, mAuthController, mUdfpsControllerProvider, mDozeLog); } @Test @@ -233,4 +251,56 @@ public class DozeScreenStateTest extends SysuiTestCase { assertEquals(Display.STATE_OFF, mServiceFake.screenState); } + @Test + public void testDelayEnterDozeScreenState_whenUdfpsFingerDown() { + // GIVEN AOD is initialized + when(mDozeParameters.shouldControlScreenOff()).thenReturn(true); + mHandlerFake.setMode(QUEUEING); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mHandlerFake.dispatchQueuedMessages(); + + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + + // WHEN udfps is activated (fingerDown) + when(mUdfpsController.isFingerDown()).thenReturn(true); + mHandlerFake.dispatchQueuedMessages(); + + // THEN the display screen state doesn't immediately change + assertEquals(Display.STATE_ON, mServiceFake.screenState); + + // WHEN udfpsController finger is no longer down and the queued messages are run + when(mUdfpsController.isFingerDown()).thenReturn(false); + mHandlerFake.dispatchQueuedMessages(); + + // THEN the display screen state will change + assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState); + } + + @Test + public void testDelayExitPulsingScreenState_whenUdfpsFingerDown() { + // GIVEN we're pulsing + when(mDozeParameters.shouldControlScreenOff()).thenReturn(true); + mHandlerFake.setMode(QUEUEING); + mScreen.transitionTo(UNINITIALIZED, INITIALIZED); + mScreen.transitionTo(INITIALIZED, DOZE_AOD); + mScreen.transitionTo(DOZE_AOD, DOZE_REQUEST_PULSE); + mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING); + mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE); + mHandlerFake.dispatchQueuedMessages(); + + // WHEN udfps is activated while are transitioning back to DOZE_AOD + mScreen.transitionTo(DOZE_PULSE_DONE, DOZE_AOD); + when(mUdfpsController.isFingerDown()).thenReturn(true); + mHandlerFake.dispatchQueuedMessages(); + + // THEN the display screen state doesn't immediately change + assertEquals(Display.STATE_ON, mServiceFake.screenState); + + // WHEN udfpsController finger is no longer down and the queued messages are run + when(mUdfpsController.isFingerDown()).thenReturn(false); + mHandlerFake.dispatchQueuedMessages(); + + // THEN the display screen state will change + assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState); + } }
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 10997fab081f..9577c7a2d6fa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -45,6 +45,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dock.DockManager; import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent; import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeThreadFactory; import com.android.systemui.util.sensors.AsyncSensorManager; @@ -83,6 +84,8 @@ public class DozeTriggersTest extends SysuiTestCase { private AuthController mAuthController; @Mock private UiEventLogger mUiEventLogger; + @Mock + private KeyguardStateController mKeyguardStateController; private DozeTriggers mTriggers; private FakeSensorManager mSensors; @@ -114,7 +117,7 @@ public class DozeTriggersTest extends SysuiTestCase { mTriggers = new DozeTriggers(mContext, mHost, config, dozeParameters, asyncSensorManager, wakeLock, mDockManager, mProximitySensor, mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(), - mAuthController, mExecutor, mUiEventLogger); + mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController); mTriggers.setDozeMachine(mMachine); waitForSensorManager(); } @@ -217,6 +220,32 @@ public class DozeTriggersTest extends SysuiTestCase { } @Test + public void testPickupGesture() { + // GIVEN device is in doze (screen blank, but running doze sensors) + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + + // WHEN the pick up gesture is triggered and keyguard isn't occluded + when(mKeyguardStateController.isOccluded()).thenReturn(false); + mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null); + + // THEN wakeup + verify(mMachine).wakeUp(); + } + + @Test + public void testPickupGestureDroppedKeyguardOccluded() { + // GIVEN device is in doze (screen blank, but running doze sensors) + when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE); + + // WHEN the pick up gesture is triggered and keyguard IS occluded + when(mKeyguardStateController.isOccluded()).thenReturn(true); + mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null); + + // THEN never wakeup + verify(mMachine, never()).wakeUp(); + } + + @Test public void testOnSensor_Fingerprint() { // GIVEN dozing state when(mMachine.getState()).thenReturn(DOZE_AOD); diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt index 03248f7e3a70..511848d8a3af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt @@ -22,11 +22,13 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.UserInfo +import android.os.Process.SYSTEM_UID import android.os.UserHandle import android.permission.PermGroupUsage import android.permission.PermissionManager import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.appops.AppOpsController import com.android.systemui.plugins.ActivityStarter @@ -53,6 +55,7 @@ import org.mockito.Mockito.`when` import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.mock import org.mockito.Mockito.never +import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -96,6 +99,8 @@ class PrivacyDialogControllerTest : SysuiTestCase() { private lateinit var activityStartedCaptor: ArgumentCaptor<ActivityStarter.Callback> @Captor private lateinit var intentCaptor: ArgumentCaptor<Intent> + @Mock + private lateinit var uiEventLogger: UiEventLogger private val backgroundExecutor = FakeExecutor(FakeSystemClock()) private val uiExecutor = FakeExecutor(FakeSystemClock()) @@ -136,6 +141,7 @@ class PrivacyDialogControllerTest : SysuiTestCase() { privacyLogger, keyguardStateController, appOpsController, + uiEventLogger, dialogProvider ) } @@ -550,6 +556,49 @@ class PrivacyDialogControllerTest : SysuiTestCase() { verify(dialog, never()).dismiss() } + @Test + fun testCallOnSecondaryUser() { + // Calls happen in + val usage = createMockPermGroupUsage(uid = SYSTEM_UID, isPhoneCall = true) + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + `when`(userTracker.userProfiles).thenReturn(listOf( + UserInfo(ENT_USER_ID, "", 0) + )) + + controller.showDialog(context) + exhaustExecutors() + + verify(dialog).show() + } + + @Test + fun testStartActivityLogs() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + controller.showDialog(context) + exhaustExecutors() + + dialogProvider.starter?.invoke(TEST_PACKAGE_NAME, USER_ID) + verify(uiEventLogger).log(PrivacyDialogEvent.PRIVACY_DIALOG_ITEM_CLICKED_TO_APP_SETTINGS, + USER_ID, TEST_PACKAGE_NAME) + } + + @Test + fun testDismissedDialogLogs() { + val usage = createMockPermGroupUsage() + `when`(permissionManager.getIndicatorAppOpUsageData(anyBoolean())).thenReturn(listOf(usage)) + controller.showDialog(context) + exhaustExecutors() + + verify(dialog).addOnDismissListener(capture(dialogDismissedCaptor)) + + dialogDismissedCaptor.value.onDialogDismissed() + + controller.dismissDialog() + + verify(uiEventLogger, times(1)).log(PrivacyDialogEvent.PRIVACY_DIALOG_DISMISSED) + } + private fun exhaustExecutors() { FakeExecutor.exhaustExecutors(backgroundExecutor, uiExecutor) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index 3ee3e55c749a..7f89b2629a6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { () -> mock(AutoTileManager.class), mock(DumpManager.class), mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)), mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class), - mock(SecureSettings.class), mock(CustomTileStatePersister.class)); + mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags); qs.setHost(host); qs.setListening(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java index 84bc12f6e922..0b67c9c51079 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java @@ -60,6 +60,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -120,6 +121,8 @@ public class QSTileHostTest extends SysuiTestCase { private SecureSettings mSecureSettings; @Mock private CustomTileStatePersister mCustomTileStatePersister; + @Mock + private FeatureFlags mFeatureFlags; private Handler mHandler; private TestableLooper mLooper; @@ -137,8 +140,9 @@ public class QSTileHostTest extends SysuiTestCase { mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler, mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager, mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker, - mSecureSettings, mCustomTileStatePersister); + mSecureSettings, mCustomTileStatePersister, mFeatureFlags); setUpTileFactory(); + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); } private void setUpTileFactory() { @@ -166,13 +170,13 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpecs_emptySetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, ""); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags); assertFalse(tiles.isEmpty()); } @Test public void testLoadTileSpecs_nullSetting() { - List<String> tiles = QSTileHost.loadTileSpecs(mContext, null); + List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags); assertFalse(tiles.isEmpty()); } @@ -186,6 +190,55 @@ public class QSTileHostTest extends SysuiTestCase { } @Test + public void testRemoveWifiAndCellularWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2"); + + assertEquals("internet", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec1", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiAndCellularWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveWifiWithoutInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(1)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testRemoveCellWithInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + assertEquals("internet", mQSTileHost.mTileSpecs.get(2)); + } + + @Test + public void testNoWifiNoCellularNoInternet() { + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true); + mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2"); + + assertEquals("spec1", mQSTileHost.mTileSpecs.get(0)); + assertEquals("spec2", mQSTileHost.mTileSpecs.get(1)); + } + + @Test public void testSpecWithInvalidDoesNotUseDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles, "spec1,spec2"); @@ -318,7 +371,7 @@ public class QSTileHostTest extends SysuiTestCase { @Test public void testLoadTileSpec_repeated() { - List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags); assertEquals(2, specs.size()); assertEquals("spec1", specs.get(0)); @@ -329,7 +382,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedInDefault() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1,spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -340,7 +393,7 @@ public class QSTileHostTest extends SysuiTestCase { public void testLoadTileSpec_repeatedDefaultAndSetting() { mContext.getOrCreateTestableResources() .addOverride(R.string.quick_settings_tiles_default, "spec1"); - List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1"); + List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags); // Remove spurious tiles, like dbg:mem specs.removeIf(spec -> !"spec1".equals(spec)); @@ -378,11 +431,12 @@ public class QSTileHostTest extends SysuiTestCase { Provider<AutoTileManager> autoTiles, DumpManager dumpManager, BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger, UiEventLogger uiEventLogger, UserTracker userTracker, - SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) { + SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister, + FeatureFlags featureFlags) { super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager, tunerService, autoTiles, dumpManager, broadcastDispatcher, Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings, - customTileStatePersister); + customTileStatePersister, featureFlags); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 4efcc5c3fc73..c5b67091d197 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.qs.QSTileHost; import com.android.systemui.settings.UserTracker; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase { private PackageManager mPackageManager; @Mock private UserTracker mUserTracker; + @Mock + private FeatureFlags mFeatureFlags; @Captor private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor; @@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase { } } ).when(mQSTileHost).createTile(anyString()); - + when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false); FakeSystemClock clock = new FakeSystemClock(); mMainExecutor = new FakeExecutor(clock); mBgExecutor = new FakeExecutor(clock); mTileQueryHelper = new TileQueryHelper( - mContext, mUserTracker, mMainExecutor, mBgExecutor); + mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags); mTileQueryHelper.setListener(mListener); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index 2b1840462291..01fa222896d3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger; import com.android.systemui.qs.tileimpl.QSFactoryImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.phone.AutoTileManager; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase { private UserTracker mUserTracker; @Mock private SecureSettings mSecureSettings; + @Mock + private FeatureFlags mFeatureFlags; @Before public void setUp() throws Exception { @@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase { mUiEventLogger, mUserTracker, mSecureSettings, - mock(CustomTileStatePersister.class)); + mock(CustomTileStatePersister.class), + mFeatureFlags); mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher, mUserTracker); } 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 baddacc3e6f5..18f48a36100c 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 @@ -444,6 +444,47 @@ public class InternetDialogControllerTest extends SysuiTestCase { verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry); } + @Test + public void onAccessPointsChanged_fourWifiEntries_callbackCutMore() { + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(true); + mAccessPoints.clear(); + mAccessPoints.add(mWifiEntry1); + mAccessPoints.add(mWifiEntry2); + mAccessPoints.add(mWifiEntry3); + mAccessPoints.add(mWifiEntry4); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.clear(); + mWifiEntries.add(mWifiEntry1); + mWifiEntries.add(mWifiEntry2); + mWifiEntries.add(mWifiEntry3); + mWifiEntries.add(mWifiEntry4); + verify(mInternetDialogCallback) + .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */); + + // If the Ethernet exists, then Wi-Fi entries will cut last one. + reset(mInternetDialogCallback); + mInternetDialogController.mHasEthernet = true; + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.remove(mWifiEntry4); + verify(mInternetDialogCallback) + .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */); + + // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one. + reset(mInternetDialogCallback); + mInternetDialogController.setAirplaneModeEnabled(false); + + mInternetDialogController.onAccessPointsChanged(mAccessPoints); + + mWifiEntries.remove(mWifiEntry3); + verify(mInternetDialogCallback) + .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */); + } + private String getResourcesString(String name) { return mContext.getResources().getString(getResourcesId(name)); } 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 fa9c0538e9bd..c42b64a09985 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 @@ -67,6 +67,7 @@ public class InternetDialogTest extends SysuiTestCase { private InternetDialog mInternetDialog; private View mDialogView; private View mSubTitle; + private LinearLayout mEthernet; private LinearLayout mMobileDataToggle; private LinearLayout mWifiToggle; private LinearLayout mConnectedWifi; @@ -97,6 +98,7 @@ public class InternetDialogTest extends SysuiTestCase { mDialogView = mInternetDialog.mDialogView; mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle); + mEthernet = mDialogView.requireViewById(R.id.ethernet_layout); mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout); mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout); mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout); @@ -139,6 +141,46 @@ public class InternetDialogTest extends SysuiTestCase { } @Test + public void updateDialog_apmOffAndHasEthernet_showEthernet() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); + when(mInternetDialogController.hasEthernet()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateDialog_apmOffAndNoEthernet_hideEthernet() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false); + when(mInternetDialogController.hasEthernet()).thenReturn(false); + + mInternetDialog.updateDialog(); + + assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void updateDialog_apmOnAndHasEthernet_showEthernet() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); + when(mInternetDialogController.hasEthernet()).thenReturn(true); + + mInternetDialog.updateDialog(); + + assertThat(mEthernet.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void updateDialog_apmOnAndNoEthernet_hideEthernet() { + when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); + when(mInternetDialogController.hasEthernet()).thenReturn(false); + + mInternetDialog.updateDialog(); + + assertThat(mEthernet.getVisibility()).isEqualTo(View.GONE); + } + + @Test public void updateDialog_withApmOn_mobileDataLayoutGone() { when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true); 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 60f0b68acac3..4276f7ce7b12 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 @@ -274,6 +274,26 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { } @Test + public void onBiometricAuthenticated_onLockScreen() { + // GIVEN not dozing + when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true); + + // WHEN we want to unlock collapse + mBiometricUnlockController.startWakeAndUnlock( + BiometricUnlockController.MODE_UNLOCK_COLLAPSING); + + // THEN we collpase the panels and notify authenticated + verify(mShadeController).animateCollapsePanels( + /* flags */ anyInt(), + /* force */ eq(true), + /* delayed */ eq(false), + /* speedUpFactor */ anyFloat() + ); + verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated( + /* strongAuth */ eq(false)); + } + + @Test public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() { reset(mUpdateMonitor); mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index f32aa2295cb8..9da6d528a967 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -157,6 +157,9 @@ public final class CachedAppOptimizer { static final int SYNC_RECEIVED_WHILE_FROZEN = 1; static final int ASYNC_RECEIVED_WHILE_FROZEN = 2; + // Bitfield values for sync transactions received by frozen binder threads + static final int TXNS_PENDING_WHILE_FROZEN = 4; + /** * This thread must be moved to the system background cpuset. * If that doesn't happen, it's probably going to draw a lot of power. @@ -611,8 +614,9 @@ public final class CachedAppOptimizer { * binder for the specificed pid. * * @throws RuntimeException in case a flush/freeze operation could not complete successfully. + * @return 0 if success, or -EAGAIN indicating there's pending transaction. */ - private static native void freezeBinder(int pid, boolean freeze); + private static native int freezeBinder(int pid, boolean freeze); /** * Retrieves binder freeze info about a process. @@ -948,7 +952,7 @@ public final class CachedAppOptimizer { int freezeInfo = getBinderFreezeInfo(pid); if ((freezeInfo & SYNC_RECEIVED_WHILE_FROZEN) != 0) { - Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " " + Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " received sync transactions while frozen, killing"); app.killLocked("Sync transaction while in frozen state", ApplicationExitInfo.REASON_OTHER, @@ -956,8 +960,8 @@ public final class CachedAppOptimizer { processKilled = true; } - if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0) { - Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " " + if ((freezeInfo & ASYNC_RECEIVED_WHILE_FROZEN) != 0 && DEBUG_FREEZER) { + Slog.d(TAG_AM, "pid " + pid + " " + app.processName + " received async transactions while frozen"); } } catch (Exception e) { @@ -1292,7 +1296,9 @@ public final class CachedAppOptimizer { public void handleMessage(Message msg) { switch (msg.what) { case SET_FROZEN_PROCESS_MSG: - freezeProcess((ProcessRecord) msg.obj); + synchronized (mAm) { + freezeProcess((ProcessRecord) msg.obj); + } break; case REPORT_UNFREEZE_MSG: int pid = msg.arg1; @@ -1306,6 +1312,15 @@ public final class CachedAppOptimizer { } } + @GuardedBy({"mAm", "mProcLock"}) + private void rescheduleFreeze(final ProcessRecord proc, final String reason) { + Slog.d(TAG_AM, "Reschedule freeze for process " + proc.getPid() + + " " + proc.processName + " (" + reason + ")"); + unfreezeAppLSP(proc); + freezeAppAsyncLSP(proc); + } + + @GuardedBy({"mAm"}) private void freezeProcess(final ProcessRecord proc) { int pid = proc.getPid(); // Unlocked intentionally final String name = proc.processName; @@ -1355,10 +1370,15 @@ public final class CachedAppOptimizer { return; } + Slog.d(TAG_AM, "freezing " + pid + " " + name); + // Freeze binder interface before the process, to flush any // transactions that might be pending. try { - freezeBinder(pid, true); + if (freezeBinder(pid, true) != 0) { + rescheduleFreeze(proc, "outstanding txns"); + return; + } } catch (RuntimeException e) { Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); mFreezeHandler.post(() -> { @@ -1404,24 +1424,36 @@ public final class CachedAppOptimizer { try { // post-check to prevent races + int freezeInfo = getBinderFreezeInfo(pid); + + if ((freezeInfo & TXNS_PENDING_WHILE_FROZEN) != 0) { + synchronized (mProcLock) { + rescheduleFreeze(proc, "new pending txns"); + } + return; + } + } catch (RuntimeException e) { + Slog.e(TAG_AM, "Unable to freeze binder for " + pid + " " + name); + mFreezeHandler.post(() -> { + synchronized (mAm) { + proc.killLocked("Unable to freeze binder interface", + ApplicationExitInfo.REASON_OTHER, + ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true); + } + }); + } + + try { + // post-check to prevent races if (mProcLocksReader.hasFileLocks(pid)) { if (DEBUG_FREEZER) { Slog.d(TAG_AM, name + " (" + pid + ") holds file locks, reverting freeze"); } - - synchronized (mAm) { - synchronized (mProcLock) { - unfreezeAppLSP(proc); - } - } + unfreezeAppLSP(proc); } } catch (Exception e) { Slog.e(TAG_AM, "Unable to check file locks for " + name + "(" + pid + "): " + e); - synchronized (mAm) { - synchronized (mProcLock) { - unfreezeAppLSP(proc); - } - } + unfreezeAppLSP(proc); } } diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index e022e977e02f..2f20efbf5730 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -84,6 +84,7 @@ public class SettingsToPropertiesMapper { DeviceConfig.NAMESPACE_CONNECTIVITY, DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT, DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS, + DeviceConfig.NAMESPACE_LMKD_NATIVE, DeviceConfig.NAMESPACE_MEDIA_NATIVE, DeviceConfig.NAMESPACE_NETD_NATIVE, DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java index 9d911e0a320b..b405be75bdf1 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java @@ -166,13 +166,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp @Override protected void stopHalOperation() { UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController); - try { - mCancellationSignal.cancel(); - } catch (RemoteException e) { - Slog.e(TAG, "Remote exception", e); - onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, - 0 /* vendorCode */); - mCallback.onClientFinished(this, false /* success */); + if (mCancellationSignal != null) { + try { + mCancellationSignal.cancel(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE, + 0 /* vendorCode */); + mCallback.onClientFinished(this, false /* success */); + } + } else { + Slog.e(TAG, "cancellation signal was null"); } } diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index 382398a210bb..e0cc8e182079 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -352,7 +352,7 @@ public class Vcn extends Handler { } private void handleSafeModeStatusChanged() { - logDbg("VcnGatewayConnection safe mode status changed"); + logVdbg("VcnGatewayConnection safe mode status changed"); boolean hasSafeModeGatewayConnection = false; // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode @@ -368,7 +368,7 @@ public class Vcn extends Handler { hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE; if (oldStatus != mCurrentStatus) { mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection); - logDbg( + logInfo( "Safe mode " + (mCurrentStatus == VCN_STATUS_CODE_SAFE_MODE ? "entered" : "exited")); } @@ -539,6 +539,16 @@ public class Vcn extends Handler { Slog.d(TAG, getLogPrefix() + msg, tr); } + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log(getLogPrefix() + "INFO: " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 450257fcdecb..7dec4e785f5c 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -1677,10 +1677,8 @@ public class VcnGatewayConnection extends StateMachine { mFailedAttempts = 0; cancelSafeModeAlarm(); - if (mIsInSafeMode) { - mIsInSafeMode = false; - mGatewayStatusCallback.onSafeModeStatusChanged(); - } + mIsInSafeMode = false; + mGatewayStatusCallback.onSafeModeStatusChanged(); } protected void applyTransform( diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 80bc16a9b052..a51ed09790a4 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -208,7 +208,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub * wallpaper set and is created for the first time. The CLOSE_WRITE is triggered * every time the wallpaper is changed. */ - private class WallpaperObserver extends FileObserver { + class WallpaperObserver extends FileObserver { final int mUserId; final WallpaperData mWallpaper; @@ -226,7 +226,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mWallpaperLockFile = new File(mWallpaperDir, WALLPAPER_LOCK_ORIG); } - private WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) { + WallpaperData dataForEvent(boolean sysChanged, boolean lockChanged) { WallpaperData wallpaper = null; synchronized (mLock) { if (lockChanged) { @@ -309,9 +309,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } wallpaper.imageWallpaperPending = false; if (sysWallpaperChanged) { + IRemoteCallback.Stub callback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "publish system wallpaper changed!"); + } + notifyWallpaperChanged(wallpaper); + } + }; // If this was the system wallpaper, rebind... bindWallpaperComponentLocked(mImageWallpaper, true, - false, wallpaper, null); + false, wallpaper, callback); notifyColorsWhich |= FLAG_SYSTEM; } if (lockWallpaperChanged @@ -331,15 +340,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } saveSettingsLocked(wallpaper.userId); - - // Publish completion *after* we've persisted the changes - if (wallpaper.setComplete != null) { - try { - wallpaper.setComplete.onWallpaperChanged(); - } catch (RemoteException e) { - // if this fails we don't really care; the setting app may just - // have crashed and that sort of thing is a fact of life. - } + // Notify the client immediately if only lockscreen wallpaper changed. + if (lockWallpaperChanged && !sysWallpaperChanged) { + notifyWallpaperChanged(wallpaper); } } } @@ -353,6 +356,18 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } + private void notifyWallpaperChanged(WallpaperData wallpaper) { + // Publish completion *after* we've persisted the changes + if (wallpaper.setComplete != null) { + try { + wallpaper.setComplete.onWallpaperChanged(); + } catch (RemoteException e) { + // if this fails we don't really care; the setting app may just + // have crashed and that sort of thing is a fact of life. + } + } + } + private void notifyLockWallpaperChanged() { final IWallpaperManagerCallback cb = mKeyguardListener; if (cb != null) { @@ -364,7 +379,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - private void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { + void notifyWallpaperColorsChanged(@NonNull WallpaperData wallpaper, int which) { if (wallpaper.connection != null) { wallpaper.connection.forEachDisplayConnector(connector -> { notifyWallpaperColorsChangedOnDisplay(wallpaper, which, connector.mDisplayId); @@ -568,7 +583,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped * for display. */ - private void generateCrop(WallpaperData wallpaper) { + void generateCrop(WallpaperData wallpaper) { boolean success = false; // Only generate crop for default display. @@ -2834,7 +2849,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return false; } - private boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, + boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) { if (DEBUG_LIVE) { Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName); @@ -3121,7 +3136,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub return new JournaledFile(new File(base), new File(base + ".tmp")); } - private void saveSettingsLocked(int userId) { + void saveSettingsLocked(int userId) { JournaledFile journal = makeJournaledFile(userId); FileOutputStream fstream = null; try { @@ -3270,7 +3285,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub * Important: this method loads settings to initialize the given user's wallpaper data if * there is no current in-memory state. */ - private WallpaperData getWallpaperSafeLocked(int userId, int which) { + WallpaperData getWallpaperSafeLocked(int userId, int which) { // We're setting either just system (work with the system wallpaper), // both (also work with the system wallpaper), or just the lock // wallpaper (update against the existing lock wallpaper if any). diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index d13c8ba96d48..0afc76d2ca30 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2253,6 +2253,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + void removeStartingWindowIfNeeded() { + // Removing the task snapshot after the task is actually focused (see + // Task#onWindowFocusChanged). Since some of the app contents may draw in this time and + // requires more times to draw finish, in case flicking may happen when removing the task + // snapshot too early. (i.e. Showing IME.) + if ((mStartingData instanceof SnapshotStartingData) && !getTask().isFocused()) { + return; + } + removeStartingWindow(); + } + void removeStartingWindow() { removeStartingWindowAnimation(true /* prepareAnimation */); } @@ -5824,7 +5835,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // own stuff. win.cancelAnimation(); } - removeStartingWindow(); + removeStartingWindowIfNeeded(); updateReportedVisibilityLocked(); } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 73d6cecd9155..c9db14de507c 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -444,7 +444,9 @@ public class DisplayRotation { } if (mDisplayContent.mFixedRotationTransitionListener - .isTopFixedOrientationRecentsAnimating()) { + .isTopFixedOrientationRecentsAnimating() + // If screen is off or the device is going to sleep, then still allow to update. + && mService.mPolicy.okToAnimate(false /* ignoreScreenOn */)) { // During the recents animation, the closing app might still be considered on top. // In order to ignore its requested orientation to avoid a sensor led rotation (e.g // user rotating the device while the recents animation is running), we ignore diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 18ea738b08ce..aa257f847e25 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -464,7 +464,8 @@ class DragState { if (mDragInProgress && isValidDropTarget(newWin, containsAppExtras, interceptsGlobalDrag)) { // Only allow the extras to be dispatched to a global-intercepting drag target ClipData data = interceptsGlobalDrag ? mData.copyForTransferWithActivityInfo() : null; - DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, touchX, touchY, + DragEvent event = obtainDragEvent(DragEvent.ACTION_DRAG_STARTED, + newWin.translateToWindowX(touchX), newWin.translateToWindowY(touchY), data, false /* includeDragSurface */, null /* dragAndDropPermission */); try { diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index da47328691c0..ed1e784bf275 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -90,6 +90,24 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider { onSourceChanged(); } + @Override + protected boolean updateClientVisibility(InsetsControlTarget caller) { + boolean changed = super.updateClientVisibility(caller); + if (changed && caller.getRequestedVisibility(mSource.getType())) { + reportImeDrawnForOrganizer(caller); + } + return changed; + } + + private void reportImeDrawnForOrganizer(InsetsControlTarget caller) { + if (caller.getWindow() != null && caller.getWindow().getTask() != null) { + if (caller.getWindow().getTask().isOrganized()) { + mWin.mWmService.mAtmService.mTaskOrganizerController.reportImeDrawnOnTask( + caller.getWindow().getTask()); + } + } + } + private void onSourceChanged() { if (mLastSource.equals(mSource)) { return; diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index fe1020c86041..cf0f973fa7db 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -106,13 +106,13 @@ class KeyguardController { } /** - * @return {@code true} for default display when AOD is showing. Otherwise, same as - * {@link #isKeyguardOrAodShowing(int)} + * @return {@code true} for default display when AOD is showing, not going away. Otherwise, same + * as {@link #isKeyguardOrAodShowing(int)} * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic. */ boolean isKeyguardUnoccludedOrAodShowing(int displayId) { if (displayId == DEFAULT_DISPLAY && mAodShowing) { - return true; + return !mKeyguardGoingAway; } return isKeyguardOrAodShowing(displayId); } @@ -477,7 +477,7 @@ class KeyguardController { final KeyguardDisplayState state = getDisplayState(displayId); if (isKeyguardUnoccludedOrAodShowing(displayId)) { state.mSleepTokenAcquirer.acquire(displayId); - } else if (!isKeyguardUnoccludedOrAodShowing(displayId)) { + } else { state.mSleepTokenAcquirer.release(displayId); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index ced5af126e49..364594e4286a 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5144,7 +5144,7 @@ class Task extends WindowContainer<WindowContainer> { /** * @return true if the task is currently focused. */ - private boolean isFocused() { + boolean isFocused() { if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) { return false; } @@ -5206,6 +5206,10 @@ class Task extends WindowContainer<WindowContainer> { * @param hasFocus */ void onWindowFocusChanged(boolean hasFocus) { + final ActivityRecord topAct = getTopVisibleActivity(); + if (topAct != null && (topAct.mStartingData instanceof SnapshotStartingData)) { + topAct.removeStartingWindowIfNeeded(); + } updateShadowsRadius(hasFocus, getSyncTransaction()); // TODO(b/180525887): Un-comment once there is resolution on the bug. // dispatchTaskInfoChangedIfNeeded(false /* force */); diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 09c5581385dd..88467baa6c34 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -733,6 +733,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { mPendingTaskEvents.clear(); } + void reportImeDrawnOnTask(Task task) { + final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder()); + if (state != null) { + try { + state.mOrganizer.mTaskOrganizer.onImeDrawnOnTask(task.mTaskId); + } catch (RemoteException e) { + Slog.e(TAG, "Exception sending onImeDrawnOnTask callback", e); + } + } + } + void onTaskInfoChanged(Task task, boolean force) { if (!task.mTaskAppearedSent) { // Skip if task still not appeared. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 2913e1071ed6..e3b25a5fda3e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2717,8 +2717,8 @@ public class WindowManagerService extends IWindowManager.Stub } @Override - public boolean attachWindowContextToDisplayArea(IBinder clientToken, int type, int displayId, - Bundle options) { + public Configuration attachWindowContextToDisplayArea(IBinder clientToken, int + type, int displayId, Bundle options) { final boolean callerCanManageAppTokens = checkCallingPermission(MANAGE_APP_TOKENS, "attachWindowContextToDisplayArea", false /* printLog */); final int callingUid = Binder.getCallingUid(); @@ -2729,15 +2729,17 @@ public class WindowManagerService extends IWindowManager.Stub if (dc == null) { ProtoLog.w(WM_ERROR, "attachWindowContextToDisplayArea: trying to attach" + " to a non-existing display:%d", displayId); - return false; + return null; } // TODO(b/155340867): Investigate if we still need roundedCornerOverlay after // the feature b/155340867 is completed. final DisplayArea da = dc.findAreaForWindowType(type, options, callerCanManageAppTokens, false /* roundedCornerOverlay */); + // TODO(b/190019118): Avoid to send onConfigurationChanged because it has been done + // in return value of attachWindowContextToDisplayArea. mWindowContextListenerController.registerWindowContainerListener(clientToken, da, callingUid, type, options); - return true; + return da.getConfiguration(); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp index e319e3febc21..4190a91710fc 100644 --- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp +++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp @@ -55,6 +55,7 @@ using android::base::unique_fd; #define SYNC_RECEIVED_WHILE_FROZEN (1) #define ASYNC_RECEIVED_WHILE_FROZEN (2) +#define TXNS_PENDING_WHILE_FROZEN (4) namespace android { @@ -232,17 +233,20 @@ static void com_android_server_am_CachedAppOptimizer_compactProcess(JNIEnv*, job compactProcessOrFallback(pid, compactionFlags); } -static void com_android_server_am_CachedAppOptimizer_freezeBinder( +static jint com_android_server_am_CachedAppOptimizer_freezeBinder( JNIEnv *env, jobject clazz, jint pid, jboolean freeze) { - if (IPCThreadState::freeze(pid, freeze, 100 /* timeout [ms] */) != 0) { + jint retVal = IPCThreadState::freeze(pid, freeze, 100 /* timeout [ms] */); + if (retVal != 0 && retVal != -EAGAIN) { jniThrowException(env, "java/lang/RuntimeException", "Unable to freeze/unfreeze binder"); } + + return retVal; } static jint com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv *env, jobject clazz, jint pid) { - bool syncReceived = false, asyncReceived = false; + uint32_t syncReceived = 0, asyncReceived = 0; int error = IPCThreadState::getProcessFreezeInfo(pid, &syncReceived, &asyncReceived); @@ -252,13 +256,12 @@ static jint com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo(JNIEnv jint retVal = 0; - if(syncReceived) { - retVal |= SYNC_RECEIVED_WHILE_FROZEN;; - } - - if(asyncReceived) { - retVal |= ASYNC_RECEIVED_WHILE_FROZEN; - } + // bit 0 of sync_recv goes to bit 0 of retVal + retVal |= syncReceived & SYNC_RECEIVED_WHILE_FROZEN; + // bit 0 of async_recv goes to bit 1 of retVal + retVal |= (asyncReceived << 1) & ASYNC_RECEIVED_WHILE_FROZEN; + // bit 1 of sync_recv goes to bit 2 of retVal + retVal |= (syncReceived << 1) & TXNS_PENDING_WHILE_FROZEN; return retVal; } @@ -278,7 +281,7 @@ static const JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ {"compactSystem", "()V", (void*)com_android_server_am_CachedAppOptimizer_compactSystem}, {"compactProcess", "(II)V", (void*)com_android_server_am_CachedAppOptimizer_compactProcess}, - {"freezeBinder", "(IZ)V", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}, + {"freezeBinder", "(IZ)I", (void*)com_android_server_am_CachedAppOptimizer_freezeBinder}, {"getBinderFreezeInfo", "(I)I", (void*)com_android_server_am_CachedAppOptimizer_getBinderFreezeInfo}, {"getFreezerCheckPath", "()Ljava/lang/String;", diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 91d4f7e2a24d..33e32393090e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -435,7 +435,6 @@ public final class SystemServer implements Dumpable { private static final String SYSPROP_START_UPTIME = "sys.system_server.start_uptime"; private Future<?> mZygotePreload; - private Future<?> mBlobStoreServiceStart; private final SystemServerDumper mDumper = new SystemServerDumper(); @@ -2250,12 +2249,9 @@ public final class SystemServer implements Dumpable { t.traceEnd(); } - mBlobStoreServiceStart = SystemServerInitThreadPool.submit(() -> { - final TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog(); - traceLog.traceBegin(START_BLOB_STORE_SERVICE); - mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS); - traceLog.traceEnd(); - }, START_BLOB_STORE_SERVICE); + t.traceBegin(START_BLOB_STORE_SERVICE); + mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS); + t.traceEnd(); // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode) t.traceBegin("StartDreamManager"); @@ -2650,9 +2646,6 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(MEDIA_COMMUNICATION_SERVICE_CLASS); t.traceEnd(); - ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart, - START_BLOB_STORE_SERVICE); - // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; final NetworkStatsService networkStatsF = networkStats; diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java index 53483f6d70bc..a49afc75c739 100644 --- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java @@ -18,13 +18,18 @@ package com.android.server.wallpaper; import static android.app.WallpaperManager.COMMAND_REAPPLY; import static android.app.WallpaperManager.FLAG_SYSTEM; +import static android.os.FileObserver.CLOSE_WRITE; +import static android.os.UserHandle.USER_SYSTEM; import static android.view.Display.DEFAULT_DISPLAY; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.server.wallpaper.WallpaperManagerService.WALLPAPER; +import static com.android.server.wallpaper.WallpaperManagerService.WALLPAPER_CROP; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; @@ -34,6 +39,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.reset; @@ -41,6 +47,7 @@ import static org.mockito.Mockito.verify; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.ComponentName; import android.content.Context; @@ -49,8 +56,10 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ServiceInfo; +import android.graphics.Color; import android.hardware.display.DisplayManager; -import android.os.UserHandle; +import android.os.RemoteException; +import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; @@ -143,7 +152,6 @@ public class WallpaperManagerServiceTests { sContext.getTestablePermissions().setPermission( android.Manifest.permission.SET_WALLPAPER, PackageManager.PERMISSION_GRANTED); - doNothing().when(sContext).sendBroadcastAsUser(any(), any()); //Wallpaper components sWallpaperService = mock(IWallpaperConnection.Stub.class); @@ -180,6 +188,7 @@ public class WallpaperManagerServiceTests { MockitoAnnotations.initMocks(this); sContext.addMockSystemService(DisplayManager.class, mDisplayManager); + doNothing().when(sContext).sendBroadcastAsUser(any(), any()); final Display mockDisplay = mock(Display.class); doReturn(DISPLAY_SIZE_DIMENSION).when(mockDisplay).getMaximumSizeDimension(); @@ -242,13 +251,13 @@ public class WallpaperManagerServiceTests { */ @Test public void testDataCorrectAfterBoot() { - mService.switchUser(UserHandle.USER_SYSTEM, null); + mService.switchUser(USER_SYSTEM, null); final WallpaperData fallbackData = mService.mFallbackWallpaper; assertEquals("Fallback wallpaper component should be ImageWallpaper.", sImageWallpaperComponentName, fallbackData.wallpaperComponent); - verifyLastWallpaperData(UserHandle.USER_SYSTEM, sDefaultWallpaperComponent); + verifyLastWallpaperData(USER_SYSTEM, sDefaultWallpaperComponent); verifyDisplayData(); } @@ -261,7 +270,7 @@ public class WallpaperManagerServiceTests { assumeThat(sDefaultWallpaperComponent, not(CoreMatchers.equalTo(sImageWallpaperComponentName))); - final int testUserId = UserHandle.USER_SYSTEM; + final int testUserId = USER_SYSTEM; mService.switchUser(testUserId, null); verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); verifyCurrentSystemData(testUserId); @@ -281,7 +290,7 @@ public class WallpaperManagerServiceTests { */ @Test public void testSetCurrentComponent() throws Exception { - final int testUserId = UserHandle.USER_SYSTEM; + final int testUserId = USER_SYSTEM; mService.switchUser(testUserId, null); verifyLastWallpaperData(testUserId, sDefaultWallpaperComponent); verifyCurrentSystemData(testUserId); @@ -387,6 +396,42 @@ public class WallpaperManagerServiceTests { assertEquals(systemWallpaperData.primaryColors, shouldMatchSystem.primaryColors); } + @Test + public void testWallpaperManagerCallbackInRightOrder() throws RemoteException { + WallpaperData wallpaper = new WallpaperData( + USER_SYSTEM, mService.getWallpaperDir(USER_SYSTEM), WALLPAPER, WALLPAPER_CROP); + wallpaper.primaryColors = new WallpaperColors(Color.valueOf(Color.RED), + Color.valueOf(Color.BLUE), null); + + spyOn(wallpaper); + doReturn(wallpaper).when(mService).getWallpaperSafeLocked(wallpaper.userId, FLAG_SYSTEM); + doNothing().when(mService).switchWallpaper(any(), any()); + doReturn(true).when(mService) + .bindWallpaperComponentLocked(any(), anyBoolean(), anyBoolean(), any(), any()); + doNothing().when(mService).saveSettingsLocked(wallpaper.userId); + doNothing().when(mService).generateCrop(wallpaper); + + // timestamps of {ACTION_WALLPAPER_CHANGED, onWallpaperColorsChanged} + final long[] timestamps = new long[2]; + doAnswer(invocation -> timestamps[0] = SystemClock.elapsedRealtime()) + .when(sContext).sendBroadcastAsUser(any(), any()); + doAnswer(invocation -> timestamps[1] = SystemClock.elapsedRealtime()) + .when(mService).notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM); + + assertNull(wallpaper.wallpaperObserver); + mService.switchUser(wallpaper.userId, null); + assertNotNull(wallpaper.wallpaperObserver); + // We will call onEvent directly, so stop watching the file. + wallpaper.wallpaperObserver.stopWatching(); + + spyOn(wallpaper.wallpaperObserver); + doReturn(wallpaper).when(wallpaper.wallpaperObserver).dataForEvent(true, false); + wallpaper.wallpaperObserver.onEvent(CLOSE_WRITE, WALLPAPER); + + // ACTION_WALLPAPER_CHANGED should be invoked before onWallpaperColorsChanged. + assertTrue(timestamps[1] > timestamps[0]); + } + // Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for // non-current user must not bind to wallpaper service. private void verifyNoConnectionBeforeLastUser(int lastUserId) { diff --git a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java index 11554c7a7dc5..8c4b4ade233b 100644 --- a/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/uwb/UwbServiceImplTest.java @@ -82,6 +82,7 @@ public class UwbServiceImplTest { MockitoAnnotations.initMocks(this); when(mUwbInjector.getVendorService()).thenReturn(mVendorService); when(mUwbInjector.checkUwbRangingPermissionForDataDelivery(any(), any())).thenReturn(true); + when(mUwbInjector.isPersistedUwbStateEnabled()).thenReturn(true); when(mVendorService.asBinder()).thenReturn(mVendorServiceBinder); mUwbServiceImpl = new UwbServiceImpl(mContext, mUwbInjector); } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 12fc2f4ea1f4..51e289f4d833 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -1565,6 +1565,12 @@ public class DisplayContentTests extends WindowTestsBase { mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(); assertTrue(displayRotation.updateRotationUnchecked(false)); + // Rotation can be updated if the policy is not ok to animate (e.g. going to sleep). + mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity); + displayRotation.setRotation((displayRotation.getRotation() + 1) % 4); + ((TestWindowManagerPolicy) mWm.mPolicy).mOkToAnimate = false; + assertTrue(displayRotation.updateRotationUnchecked(false)); + // Rotation can be updated if the recents animation is animating but it is not on top, e.g. // switching activities in different orientations by quickstep gesture. mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(recentsActivity); @@ -2166,6 +2172,21 @@ public class DisplayContentTests extends WindowTestsBase { } @Test + public void testKeyguardGoingAwayWhileAodShown() { + mDisplayContent.getDisplayPolicy().setAwake(true); + + final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin"); + final ActivityRecord activity = appWin.mActivityRecord; + + mAtm.mKeyguardController.setKeyguardShown(true /* keyguardShowing */, + true /* aodShowing */); + assertFalse(activity.isVisibleRequested()); + + mAtm.mKeyguardController.keyguardGoingAway(0 /* flags */); + assertTrue(activity.isVisibleRequested()); + } + + @Test public void testRemoveRootTaskInWindowingModes() { removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksInWindowingModes( WINDOWING_MODE_FULLSCREEN)); diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java index f2418c68358d..a8ede13e5de6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java @@ -82,7 +82,7 @@ public class InputMethodMenuControllerTest extends WindowTestsBase { mWm.mWindowContextListenerController.registerWindowContainerListener(clientToken, dc.getImeContainer(), 1000 /* ownerUid */, TYPE_INPUT_METHOD_DIALOG, null /* options */); - return true; + return dc.getImeContainer().getConfiguration(); }).when(wms).attachWindowContextToDisplayArea(any(), eq(TYPE_INPUT_METHOD_DIALOG), anyInt(), any()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index d6a8401f5b18..ab496cf34acc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -797,6 +797,9 @@ public class WindowOrganizerTests extends WindowTestsBase { public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) { } @Override + public void onImeDrawnOnTask(int taskId) throws RemoteException { + } + @Override public void onAppSplashScreenViewRemoved(int taskId) { } }; diff --git a/services/uwb/java/com/android/server/uwb/UwbInjector.java b/services/uwb/java/com/android/server/uwb/UwbInjector.java index 64f1da1c8e16..7445e7f0c591 100644 --- a/services/uwb/java/com/android/server/uwb/UwbInjector.java +++ b/services/uwb/java/com/android/server/uwb/UwbInjector.java @@ -21,10 +21,13 @@ import static android.content.PermissionChecker.PERMISSION_GRANTED; import android.annotation.NonNull; import android.content.AttributionSource; +import android.content.ContentResolver; import android.content.Context; import android.content.PermissionChecker; import android.os.IBinder; import android.os.ServiceManager; +import android.provider.Settings; +import android.uwb.AdapterState; import android.uwb.IUwbAdapter; @@ -80,4 +83,16 @@ public class UwbInjector { mContext, UWB_RANGING, -1, attributionSource, message); return permissionCheckResult == PERMISSION_GRANTED; } + + /** Returns true if UWB state saved in Settings is enabled. */ + public boolean isPersistedUwbStateEnabled() { + final ContentResolver cr = mContext.getContentResolver(); + try { + return Settings.Global.getInt(cr, Settings.Global.UWB_ENABLED) + == AdapterState.STATE_ENABLED_ACTIVE; + } catch (Settings.SettingNotFoundException e) { + Settings.Global.putInt(cr, Settings.Global.UWB_ENABLED, AdapterState.STATE_DISABLED); + return false; + } + } } diff --git a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java index 4dd26a66cf0e..da11a9acf2c1 100644 --- a/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java +++ b/services/uwb/java/com/android/server/uwb/UwbServiceImpl.java @@ -18,13 +18,16 @@ package com.android.server.uwb; import android.annotation.NonNull; import android.content.AttributionSource; +import android.content.ContentResolver; import android.content.Context; import android.os.Binder; import android.os.IBinder; import android.os.PersistableBundle; import android.os.RemoteException; +import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; +import android.uwb.AdapterState; import android.uwb.IUwbAdapter; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbRangingCallbacks; @@ -225,13 +228,15 @@ public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRec mVendorUwbAdapter = null; } - private synchronized IUwbAdapter getVendorUwbAdapter() throws IllegalStateException { + private synchronized IUwbAdapter getVendorUwbAdapter() + throws IllegalStateException, RemoteException { if (mVendorUwbAdapter != null) return mVendorUwbAdapter; mVendorUwbAdapter = mUwbInjector.getVendorService(); if (mVendorUwbAdapter == null) { throw new IllegalStateException("No vendor service found!"); } Log.i(TAG, "Retrieved vendor service"); + mVendorUwbAdapter.setEnabled(mUwbInjector.isPersistedUwbStateEnabled()); linkToVendorServiceDeath(); return mVendorUwbAdapter; } @@ -320,6 +325,13 @@ public class UwbServiceImpl extends IUwbAdapter.Stub implements IBinder.DeathRec @Override public synchronized void setEnabled(boolean enabled) throws RemoteException { + persistUwbState(enabled); getVendorUwbAdapter().setEnabled(enabled); } + + private void persistUwbState(boolean enabled) { + final ContentResolver cr = mContext.getContentResolver(); + int state = enabled ? AdapterState.STATE_ENABLED_ACTIVE : AdapterState.STATE_DISABLED; + Settings.Global.putInt(cr, Settings.Global.UWB_ENABLED, state); + } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java index a9aeb985d115..4dc83ae98d89 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java @@ -269,13 +269,11 @@ final class HotwordDetectionConnection { Slog.v(TAG, "cancelLocked"); clearDebugHotwordLoggingTimeoutLocked(); mDebugHotwordLogging = false; - if (mRemoteHotwordDetectionService.isBound()) { - mRemoteHotwordDetectionService.unbind(); - LocalServices.getService(PermissionManagerServiceInternal.class) - .setHotwordDetectionServiceProvider(null); - mIdentity = null; - updateServiceUidForAudioPolicy(Process.INVALID_UID); - } + mRemoteHotwordDetectionService.unbind(); + LocalServices.getService(PermissionManagerServiceInternal.class) + .setHotwordDetectionServiceProvider(null); + mIdentity = null; + updateServiceUidForAudioPolicy(Process.INVALID_UID); mCancellationTaskFuture.cancel(/* may interrupt */ true); if (mAudioFlinger != null) { mAudioFlinger.unlinkToDeath(mAudioServerDeathRecipient, /* flags= */ 0); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index abab426b3252..d5be4f36145a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -14302,7 +14302,8 @@ public class TelephonyManager { if (callForwardingInfo.getNumber() == null) { throw new IllegalArgumentException("callForwarding number is null"); } - if (callForwardingInfo.getTimeoutSeconds() <= 0) { + if (callForwardingReason == CallForwardingInfo.REASON_NO_REPLY + && callForwardingInfo.getTimeoutSeconds() <= 0) { throw new IllegalArgumentException("callForwarding timeout isn't positive"); } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 0f84f6ebe522..c9a8947ab5ef 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -322,6 +322,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); verify(mSafeModeTimeoutAlarm).cancel(); assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); } @Test @@ -391,6 +392,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, false /* isInSafeMode */); assertFalse(mGatewayConnection.isInSafeMode()); } @@ -400,7 +402,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection mTestLooper.dispatchAll(); triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID); - assertFalse(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1 /* invocationCount */, false /* isInSafeMode */); // Trigger a failed validation, and the subsequent safemode timeout. triggerValidation(NetworkAgent.VALIDATION_STATUS_NOT_VALID); @@ -416,7 +418,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection runnableCaptor.getValue().run(); mTestLooper.dispatchAll(); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */); } private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() { diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index a696b3ae28f7..64d0bca15ce9 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -23,7 +23,6 @@ import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -301,6 +300,11 @@ public class VcnGatewayConnectionTestBase { expectCanceled); } + protected void verifySafeModeStateAndCallbackFired(int invocationCount, boolean isInSafeMode) { + verify(mGatewayStatusCallback, times(invocationCount)).onSafeModeStatusChanged(); + assertEquals(isInSafeMode, mGatewayConnection.isInSafeMode()); + } + protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent( @NonNull State expectedState) { // Set a VcnNetworkAgent, and expect it to be unregistered and cleared @@ -314,9 +318,8 @@ public class VcnGatewayConnectionTestBase { delayedEvent.run(); mTestLooper.dispatchAll(); - verify(mGatewayStatusCallback).onSafeModeStatusChanged(); assertEquals(expectedState, mGatewayConnection.getCurrentState()); - assertTrue(mGatewayConnection.isInSafeMode()); + verifySafeModeStateAndCallbackFired(1, true); verify(mockNetworkAgent).unregister(); assertNull(mGatewayConnection.getNetworkAgent()); |