diff options
60 files changed, 658 insertions, 431 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index af70562839ba..1aa3db6963b7 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5621,18 +5621,18 @@ package android.window { public class TaskOrganizer extends android.window.WindowOrganizer { ctor public TaskOrganizer(); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.app.ActivityManager.RunningTaskInfo createRootTask(int, int); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static boolean deleteRootTask(@NonNull android.window.WindowContainerToken); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static android.window.WindowContainerToken getImeTarget(int); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.window.WindowContainerToken getImeTarget(int); + method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getRootTasks(int, @NonNull int[]); method @BinderThread public void onBackPressedOnTaskRoot(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskAppeared(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl); method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo); method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer(); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer(); } @@ -5669,7 +5669,7 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); - method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public static void applyTransaction(@NonNull android.window.WindowContainerTransaction); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } } diff --git a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java index 95db0a26cc6e..e879091cd68e 100644 --- a/core/java/android/app/timezonedetector/TimeZoneConfiguration.java +++ b/core/java/android/app/timezonedetector/TimeZoneConfiguration.java @@ -162,9 +162,9 @@ public final class TimeZoneConfiguration implements Parcelable { @Override public String toString() { - return "TimeZoneDetectorConfiguration{" + return "TimeZoneConfiguration{" + "mUserId=" + mUserId - + "mBundle=" + mBundle + + ", mBundle=" + mBundle + '}'; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 0f1f276ce0f9..e108451b54fb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -30,7 +30,6 @@ import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; @@ -159,8 +158,6 @@ public class PackageParser { SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false); public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f; - public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO = 1.333f; - public static final float DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH = 1f; private static final int DEFAULT_MIN_SDK_VERSION = 1; private static final int DEFAULT_TARGET_SDK_VERSION = 0; @@ -4683,20 +4680,8 @@ public class PackageParser { * ratio set. */ private void setMinAspectRatio(Package owner) { - final float minAspectRatio; - if (owner.applicationInfo.minAspectRatio != 0) { - // Use the application max aspect ration as default if set. - minAspectRatio = owner.applicationInfo.minAspectRatio; - } else { - // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. - // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, - // except for watches which always supported 1:1. - minAspectRatio = owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q - ? 0 - : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH)) - ? DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH - : DEFAULT_PRE_Q_MIN_ASPECT_RATIO; - } + // Use the application max aspect ration as default if set. + final float minAspectRatio = owner.applicationInfo.minAspectRatio; for (Activity activity : owner.activities) { if (activity.hasMinAspectRatio()) { diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index 4914601b0b5a..542cfc29f1a2 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -67,7 +67,7 @@ public class ApkLiteParseUtils { * Automatically detects if the package is a monolithic style (single APK * file) or cluster style (directory of APKs). * <p> - * This performs sanity checking on cluster style packages, such as + * This performs validity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index e1f08f3e55a1..d9857e0d2328 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -18,7 +18,6 @@ package android.content.pm.parsing; import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; -import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; @@ -211,7 +210,7 @@ public class ParsingPackageUtils { * package is a monolithic style (single APK file) or cluster style * (directory of APKs). * <p> - * This performs sanity checking on cluster style packages, such as + * This performs validity checking on cluster style packages, such as * requiring identical package name and version codes, a single base APK, * and unique split names. * <p> @@ -237,7 +236,7 @@ public class ParsingPackageUtils { /** * Parse all APKs contained in the given directory, treating them as a - * single package. This also performs sanity checking, such as requiring + * single package. This also performs validity checking, such as requiring * identical package name and version codes, a single base APK, and unique * split names. * <p> @@ -2375,21 +2374,8 @@ public class ParsingPackageUtils { * ratio set. */ private void setMinAspectRatio(ParsingPackage pkg) { - final float minAspectRatio; - float packageMinAspectRatio = pkg.getMinAspectRatio(); - if (packageMinAspectRatio != 0) { - // Use the application max aspect ration as default if set. - minAspectRatio = packageMinAspectRatio; - } else { - // Default to (1.33) 4:3 aspect ratio for pre-Q apps and unset for Q and greater. - // NOTE: 4:3 was the min aspect ratio Android devices can support pre-Q per the CDD, - // except for watches which always supported 1:1. - minAspectRatio = pkg.getTargetSdkVersion() >= Build.VERSION_CODES.Q - ? 0 - : (mCallback != null && mCallback.hasFeature(FEATURE_WATCH)) - ? PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO_WATCH - : PackageParser.DEFAULT_PRE_Q_MIN_ASPECT_RATIO; - } + // Use the application max aspect ration as default if set. + final float minAspectRatio = pkg.getMinAspectRatio(); List<ParsedActivity> activities = pkg.getActivities(); int activitiesSize = activities.size(); diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 700dc66fab55..ba40459692f7 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -113,13 +113,20 @@ public class InsetsSourceConsumer { InsetsState.typeToString(control.getType()), mController.getHost().getRootViewTitle())); } - // We are loosing control if (mSourceControl == null) { + // We are loosing control mController.notifyControlRevoked(this); - // Restore server visibility. - mState.getSource(getType()).setVisible( - mController.getLastDispatchedState().getSource(getType()).isVisible()); + // Check if we need to restore server visibility. + final InsetsSource source = mState.getSource(mType); + final boolean serverVisibility = + mController.getLastDispatchedState().getSourceOrDefaultVisibility(mType); + if (source.isVisible() != serverVisibility) { + source.setVisible(serverVisibility); + mController.notifyVisibilityChanged(); + } + + // For updateCompatSysUiVisibility applyLocalVisibilityOverride(); } else { // We are gaining control, and need to run an animation since previous state diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index f035d36a0f71..78fa30358d74 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.os.RemoteException; -import android.util.Singleton; import android.view.SurfaceControl; /** @@ -135,22 +134,12 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } }; - private static IDisplayAreaOrganizerController getController() { - return IDisplayAreaOrganizerControllerSingleton.get(); + private IDisplayAreaOrganizerController getController() { + try { + return getWindowOrganizerController().getDisplayAreaOrganizerController(); + } catch (RemoteException e) { + return null; + } } - private static final Singleton<IDisplayAreaOrganizerController> - IDisplayAreaOrganizerControllerSingleton = - new Singleton<IDisplayAreaOrganizerController>() { - @Override - protected IDisplayAreaOrganizerController create() { - try { - return getWindowOrganizerController() - .getDisplayAreaOrganizerController(); - } catch (RemoteException e) { - return null; - } - } - }; - } diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java index 38fb023a0822..d8f2bb248fd1 100644 --- a/core/java/android/window/TaskOrganizer.java +++ b/core/java/android/window/TaskOrganizer.java @@ -23,9 +23,10 @@ import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.app.ActivityManager; import android.os.RemoteException; -import android.util.Singleton; import android.view.SurfaceControl; +import com.android.internal.annotations.VisibleForTesting; + import java.util.List; /** @@ -35,13 +36,25 @@ import java.util.List; @TestApi public class TaskOrganizer extends WindowOrganizer { + private ITaskOrganizerController mTaskOrganizerController; + + public TaskOrganizer() { + mTaskOrganizerController = getController(); + } + + /** @hide */ + @VisibleForTesting + public TaskOrganizer(ITaskOrganizerController taskOrganizerController) { + mTaskOrganizerController = taskOrganizerController; + } + /** * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void registerOrganizer() { try { - getController().registerTaskOrganizer(mInterface); + mTaskOrganizerController.registerTaskOrganizer(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -51,7 +64,7 @@ public class TaskOrganizer extends WindowOrganizer { @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public final void unregisterOrganizer() { try { - getController().unregisterTaskOrganizer(mInterface); + mTaskOrganizerController.unregisterTaskOrganizer(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -78,9 +91,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Creates a persistent root task in WM for a particular windowing-mode. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) { + public ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) { try { - return getController().createRootTask(displayId, windowingMode); + return mTaskOrganizerController.createRootTask(displayId, windowingMode); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -88,9 +101,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Deletes a persistent root task in WM */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static boolean deleteRootTask(@NonNull WindowContainerToken task) { + public boolean deleteRootTask(@NonNull WindowContainerToken task) { try { - return getController().deleteRootTask(task); + return mTaskOrganizerController.deleteRootTask(task); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -99,10 +112,10 @@ public class TaskOrganizer extends WindowOrganizer { /** Gets direct child tasks (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static List<ActivityManager.RunningTaskInfo> getChildTasks( + public List<ActivityManager.RunningTaskInfo> getChildTasks( @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) { try { - return getController().getChildTasks(parent, activityTypes); + return mTaskOrganizerController.getChildTasks(parent, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -111,10 +124,10 @@ public class TaskOrganizer extends WindowOrganizer { /** Gets all root tasks on a display (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static List<ActivityManager.RunningTaskInfo> getRootTasks( + public List<ActivityManager.RunningTaskInfo> getRootTasks( int displayId, @NonNull int[] activityTypes) { try { - return getController().getRootTasks(displayId, activityTypes); + return mTaskOrganizerController.getRootTasks(displayId, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -123,9 +136,9 @@ public class TaskOrganizer extends WindowOrganizer { /** Get the root task which contains the current ime target */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) @Nullable - public static WindowContainerToken getImeTarget(int display) { + public WindowContainerToken getImeTarget(int display) { try { - return getController().getImeTarget(display); + return mTaskOrganizerController.getImeTarget(display); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -136,9 +149,9 @@ public class TaskOrganizer extends WindowOrganizer { * root and thus new tasks just end up directly on the display. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) { + public void setLaunchRoot(int displayId, @NonNull WindowContainerToken root) { try { - getController().setLaunchRoot(displayId, root); + mTaskOrganizerController.setLaunchRoot(displayId, root); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -152,7 +165,7 @@ public class TaskOrganizer extends WindowOrganizer { public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task, boolean interceptBackPressed) { try { - getController().setInterceptBackPressedOnTaskRoot(task, interceptBackPressed); + mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(task, interceptBackPressed); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -181,19 +194,11 @@ public class TaskOrganizer extends WindowOrganizer { } }; - private static ITaskOrganizerController getController() { - return ITaskOrganizerControllerSingleton.get(); + private ITaskOrganizerController getController() { + try { + return getWindowOrganizerController().getTaskOrganizerController(); + } catch (RemoteException e) { + return null; + } } - - private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton = - new Singleton<ITaskOrganizerController>() { - @Override - protected ITaskOrganizerController create() { - try { - return getWindowOrganizerController().getTaskOrganizerController(); - } catch (RemoteException e) { - return null; - } - } - }; } diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java index eb9dfed7f644..1e293df38cf8 100644 --- a/core/java/android/window/TaskOrganizerTaskEmbedder.java +++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java @@ -109,7 +109,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setHidden(mTaskToken, false /* hidden */); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // TODO(b/151449487): Only call callback once we enable synchronization if (mListener != null) { mListener.onTaskVisibilityChanged(getTaskId(), true); @@ -133,7 +133,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setHidden(mTaskToken, true /* hidden */); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // TODO(b/151449487): Only call callback once we enable synchronization if (mListener != null) { mListener.onTaskVisibilityChanged(getTaskId(), false); @@ -165,7 +165,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder { WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mTaskToken, screenBounds); // TODO(b/151449487): Enable synchronization - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } /** diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index ff40ddac134e..97a97d9984f9 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -38,7 +38,7 @@ public class WindowOrganizer { * @param t The transaction to apply. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static void applyTransaction(@NonNull WindowContainerTransaction t) { + public void applyTransaction(@NonNull WindowContainerTransaction t) { try { getWindowOrganizerController().applyTransaction(t); } catch (RemoteException e) { @@ -74,7 +74,7 @@ public class WindowOrganizer { */ @Nullable @RequiresPermission(android.Manifest.permission.READ_FRAME_BUFFER) - public static SurfaceControl takeScreenshot(@NonNull WindowContainerToken token) { + public SurfaceControl takeScreenshot(@NonNull WindowContainerToken token) { try { SurfaceControl surfaceControl = new SurfaceControl(); if (getWindowOrganizerController().takeScreenshot(token, surfaceControl)) { @@ -88,7 +88,7 @@ public class WindowOrganizer { } @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - static IWindowOrganizerController getWindowOrganizerController() { + IWindowOrganizerController getWindowOrganizerController() { return IWindowOrganizerControllerSingleton.get(); } diff --git a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java index 1ec020696cf3..64e0b91ae40a 100644 --- a/core/java/com/android/internal/policy/TaskResizingAlgorithm.java +++ b/core/java/com/android/internal/policy/TaskResizingAlgorithm.java @@ -51,8 +51,6 @@ public class TaskResizingAlgorithm { public static final int CTRL_BOTTOM = 0x8; // The minimal aspect ratio which needs to be met to count as landscape (or 1/.. for portrait). - // Note: We do not use the 1.33 from the CDD here since the user is allowed to use what ever - // aspect he desires. @VisibleForTesting public static final float MIN_ASPECT = 1.2f; diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 6212bcbbc05f..7fac615aa88d 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2748,4 +2748,7 @@ enum PageId { // CATEGORY: SETTINGS // OS: R QPR ADAPTIVE_CONNECTIVITY_CATEGORY = 1850; + + // OS: R QPR2 + BLUETOOTH_PAIRING_RECEIVER = 1851; } diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 0e176b53f236..feef587dd685 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1283,7 +1283,7 @@ <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"nepoznata vrsta mreže"</string> <string name="accept" msgid="5447154347815825107">"Prihvati"</string> <string name="decline" msgid="6490507610282145874">"Odbijte"</string> - <string name="select_character" msgid="3352797107930786979">"Umetni karakter"</string> + <string name="select_character" msgid="3352797107930786979">"Umetni znak"</string> <string name="sms_control_title" msgid="4748684259903148341">"Slanje SMS poruka"</string> <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> šalje veliki broj SMS poruka. Da li želite dozvoliti ovoj aplikaciji da nastavi slanje poruka?"</string> <string name="sms_control_yes" msgid="4858845109269524622">"Dozvoli"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 0004ff1a3f13..9062435ec9ce 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1900,8 +1900,8 @@ <string name="profile_encrypted_message" msgid="1128512616293157802">"A feloldáshoz koppintson rá"</string> <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Csatlakoztatva a(z) <xliff:g id="PRODUCT_NAME">%1$s</xliff:g> eszközhöz"</string> <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Koppintson ide a fájlok megtekintéséhez"</string> - <string name="pin_target" msgid="8036028973110156895">"Rögzítés"</string> - <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítése"</string> + <string name="pin_target" msgid="8036028973110156895">"Kitűzés"</string> + <string name="pin_specific_target" msgid="7824671240625957415">"<xliff:g id="LABEL">%1$s</xliff:g> kitűzése"</string> <string name="unpin_target" msgid="3963318576590204447">"Feloldás"</string> <string name="unpin_specific_target" msgid="3859828252160908146">"<xliff:g id="LABEL">%1$s</xliff:g> rögzítésének feloldása"</string> <string name="app_info" msgid="6113278084877079851">"Alkalmazásinformáció"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 264a8fcb343d..4f66b6e8a947 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1979,7 +1979,7 @@ <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Չհաջողվեց վերականգնել դյուրանցումը, քանի որ հավելվածների ստորագրությունները տարբեր են"</string> <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Չհաջողվեց վերականգնել դյուրանցումը"</string> <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Դյուրանցումն անջատված է"</string> - <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ՀԵՌԱՑՆԵԼ"</string> + <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"ԱՊԱՏԵՂԱԴՐԵԼ"</string> <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"ԲԱՑԵԼ"</string> <string name="harmful_app_warning_title" msgid="8794823880881113856">"Հայտնաբերվել է վնասաբեր հավելված"</string> <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index a65f80c9332f..2c041dced482 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1120,7 +1120,7 @@ <string name="yes" msgid="9069828999585032361">"ОК"</string> <string name="no" msgid="5122037903299899715">"Цуцлах"</string> <string name="dialog_alert_title" msgid="651856561974090712">"Анхаар"</string> - <string name="loading" msgid="3138021523725055037">"Ачааллаж байна..."</string> + <string name="loading" msgid="3138021523725055037">"Ачаалж байна..."</string> <string name="capital_on" msgid="2770685323900821829">"Идэвхтэй"</string> <string name="capital_off" msgid="7443704171014626777">"Идэвхгүй"</string> <string name="checked" msgid="9179896827054513119">"тэмдэглэсэн"</string> 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 ea9576a511e9..f9ba695c8503 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java @@ -17,23 +17,23 @@ package com.android.wm.shell; import android.app.ActivityManager.RunningTaskInfo; -import android.app.WindowConfiguration; -import android.content.Context; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.SurfaceControl; +import android.window.ITaskOrganizerController; import android.window.TaskOrganizer; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.protolog.ShellProtoLogGroup; -import com.android.wm.shell.protolog.ShellProtoLogImpl; import java.util.ArrayList; import java.util.Arrays; /** * Unified task organizer for all components in the shell. + * TODO(b/167582004): may consider consolidating this class and TaskOrganizer */ public class ShellTaskOrganizer extends TaskOrganizer { @@ -56,6 +56,15 @@ public class ShellTaskOrganizer extends TaskOrganizer { // require us to report to both old and new listeners) private final SparseArray<Pair<RunningTaskInfo, SurfaceControl>> mTasks = new SparseArray<>(); + public ShellTaskOrganizer() { + super(); + } + + @VisibleForTesting + ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController) { + super(taskOrganizerController); + } + /** * Adds a listener for tasks in a specific windowing mode. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java index 92cee8a1a874..ff617ed466d1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerImeController.java @@ -30,7 +30,6 @@ import android.view.SurfaceControl; import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; -import android.window.WindowOrganizer; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.TransactionPool; @@ -44,6 +43,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private final SplitScreenTaskOrganizer mSplits; private final TransactionPool mTransactionPool; private final Handler mHandler; + private final TaskOrganizer mTaskOrganizer; /** * These are the y positions of the top of the IME surface when it is hidden and when it is @@ -92,10 +92,12 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor private boolean mPausedTargetAdjusted = false; private boolean mAdjustedWhileHidden = false; - DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler) { + DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler, + TaskOrganizer taskOrganizer) { mSplits = splits; mTransactionPool = pool; mHandler = handler; + mTaskOrganizer = taskOrganizer; } private DividerView getView() { @@ -111,7 +113,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } private boolean getSecondaryHasFocus(int displayId) { - WindowContainerToken imeSplit = TaskOrganizer.getImeTarget(displayId); + WindowContainerToken imeSplit = mTaskOrganizer.getImeTarget(displayId); return imeSplit != null && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } @@ -236,7 +238,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor } if (!mSplits.mSplitScreenController.getWmProxy().queueSyncTransactionIfWaiting(wct)) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java index 79bfda92bd92..00146e9447bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerView.java @@ -619,7 +619,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, mEntranceAnimationRunning = false; mExitAnimationRunning = false; if (!dismissed && !wasMinimizeInteraction) { - WindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout); + mWindowManagerProxy.applyResizeSplits(snapTarget.position, mSplitLayout); } if (mCallback != null) { mCallback.onDraggingEnd(); @@ -889,7 +889,7 @@ public class DividerView extends FrameLayout implements OnTouchListener, t.hide(sc).apply(); mTiles.releaseTransaction(t); int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; - WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout); + mWindowManagerProxy.applyResizeSplits(midPos, mSplitLayout); } void setMinimizedDockStack(boolean minimized, long animDuration, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index d5326d4845a3..eed5092ea96b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -29,9 +29,9 @@ import android.provider.Settings; import android.util.Slog; import android.view.LayoutInflater; import android.view.View; +import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; -import android.window.WindowOrganizer; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.wm.shell.R; @@ -71,6 +71,7 @@ public class SplitScreenController implements SplitScreen, private final SystemWindows mSystemWindows; final TransactionPool mTransactionPool; private final WindowManagerProxy mWindowManagerProxy; + private final TaskOrganizer mTaskOrganizer; private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners = new ArrayList<>(); @@ -106,9 +107,12 @@ public class SplitScreenController implements SplitScreen, mHandler = handler; mForcedResizableController = new ForcedResizableInfoActivityController(context, this); mTransactionPool = transactionPool; - mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler); + mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler, + shellTaskOrganizer); + mTaskOrganizer = shellTaskOrganizer; mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer); - mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler); + mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler, + shellTaskOrganizer); mRotationController = (display, fromRotation, toRotation, wct) -> { if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) { @@ -132,7 +136,7 @@ public class SplitScreenController implements SplitScreen, sdl.resizeSplits(target.position, t); if (isSplitActive() && mHomeStackResizable) { - WindowManagerProxy + mWindowManagerProxy .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t); } if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) { @@ -189,7 +193,7 @@ public class SplitScreenController implements SplitScreen, final WindowContainerTransaction tct = new WindowContainerTransaction(); int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; mSplitLayout.resizeSplits(midPos, tct); - WindowOrganizer.applyTransaction(tct); + mTaskOrganizer.applyTransaction(tct); } catch (Exception e) { Slog.e(TAG, "Failed to register docked stack listener", e); removeDivider(); @@ -208,7 +212,7 @@ public class SplitScreenController implements SplitScreen, int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; final WindowContainerTransaction tct = new WindowContainerTransaction(); mSplitLayout.resizeSplits(midPos, tct); - WindowOrganizer.applyTransaction(tct); + mTaskOrganizer.applyTransaction(tct); } else if (mSplitLayout.mDisplayLayout.rotation() == mRotateSplitLayout.mDisplayLayout.rotation()) { mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary); @@ -372,7 +376,7 @@ public class SplitScreenController implements SplitScreen, // If we are only setting focusability, a sync transaction isn't necessary (in fact it // can interrupt other animations), so see if it can be submitted on pending instead. if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java index 6d28c5e17d42..30bc43b0292f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTaskOrganizer.java @@ -31,7 +31,6 @@ import android.util.Log; import android.view.Display; import android.view.SurfaceControl; import android.view.SurfaceSession; -import android.window.TaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer; @@ -64,9 +63,9 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener { void init() throws RemoteException { synchronized (this) { try { - mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, + mPrimary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mSecondary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, + mSecondary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); } catch (Exception e) { // teardown to prevent callbacks diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java index cd96676ad1fe..015707ecc6c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/WindowManagerProxy.java @@ -83,8 +83,12 @@ class WindowManagerProxy { } }; - WindowManagerProxy(TransactionPool transactionPool, Handler handler) { + private final TaskOrganizer mTaskOrganizer; + + WindowManagerProxy(TransactionPool transactionPool, Handler handler, + TaskOrganizer taskOrganizer) { mSyncTransactionQueue = new SyncTransactionQueue(transactionPool, handler); + mTaskOrganizer = taskOrganizer; } void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout, @@ -113,18 +117,18 @@ class WindowManagerProxy { mExecutor.execute(mSetTouchableRegionRunnable); } - static void applyResizeSplits(int position, SplitDisplayLayout splitLayout) { + void applyResizeSplits(int position, SplitDisplayLayout splitLayout) { WindowContainerTransaction t = new WindowContainerTransaction(); splitLayout.resizeSplits(position, t); - WindowOrganizer.applyTransaction(t); + new WindowOrganizer().applyTransaction(t); } - private static boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out, + private boolean getHomeAndRecentsTasks(List<ActivityManager.RunningTaskInfo> out, WindowContainerToken parent) { boolean resizable = false; List<ActivityManager.RunningTaskInfo> rootTasks = parent == null - ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) - : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); + ? mTaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) + : mTaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); for (int i = 0, n = rootTasks.size(); i < n; ++i) { final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); out.add(ti); @@ -140,7 +144,7 @@ class WindowManagerProxy { * split is minimized. This actually "sticks out" of the secondary split area, but when in * minimized mode, the secondary split gets a 'negative' crop to expose it. */ - static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent, + boolean applyHomeTasksMinimized(SplitDisplayLayout layout, WindowContainerToken parent, @NonNull WindowContainerTransaction wct) { // Resize the home/recents stacks to the larger minimized-state size final Rect homeBounds; @@ -192,9 +196,9 @@ class WindowManagerProxy { // Set launchtile first so that any stack created after // getAllStackInfos and before reparent (even if unlikely) are placed // correctly. - TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); + mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); List<ActivityManager.RunningTaskInfo> rootTasks = - TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); + mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); WindowContainerTransaction wct = new WindowContainerTransaction(); if (rootTasks.isEmpty()) { return false; @@ -230,7 +234,7 @@ class WindowManagerProxy { return isHomeResizable; } - static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { + boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) { final int atype = ti.configuration.windowConfiguration.getActivityType(); return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS; } @@ -245,18 +249,18 @@ class WindowManagerProxy { boolean dismissOrMaximize) { // Set launch root first so that any task created after getChildContainers and // before reparent (pretty unlikely) are put into fullscreen. - TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); + mTaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished // plus specific APIs to clean this up. List<ActivityManager.RunningTaskInfo> primaryChildren = - TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); + mTaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); List<ActivityManager.RunningTaskInfo> secondaryChildren = - TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); + mTaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); // In some cases (eg. non-resizable is launched), system-server will leave split-screen. // as a result, the above will not capture any tasks; yet, we need to clean-up the // home task bounds. List<ActivityManager.RunningTaskInfo> freeHomeAndRecents = - TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS); + mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS); // Filter out the root split tasks freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token) || p.token.equals(tiles.mPrimary.token)); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java index 10672c8d87ad..497b6b714281 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java @@ -20,10 +20,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; import android.app.ActivityManager.RunningTaskInfo; -import android.content.res.Configuration; +import android.os.RemoteException; import android.view.SurfaceControl; +import android.window.ITaskOrganizer; +import android.window.ITaskOrganizerController; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -31,6 +35,8 @@ import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -41,6 +47,9 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public class ShellTaskOrganizerTests { + @Mock + private ITaskOrganizerController mTaskOrganizerController; + ShellTaskOrganizer mOrganizer; private class TrackingTaskListener implements ShellTaskOrganizer.TaskListener { @@ -71,7 +80,15 @@ public class ShellTaskOrganizerTests { @Before public void setUp() { - mOrganizer = new ShellTaskOrganizer(); + MockitoAnnotations.initMocks(this); + mOrganizer = new ShellTaskOrganizer(mTaskOrganizerController); + } + + @Test + public void registerOrganizer_sendRegisterTaskOrganizer() throws RemoteException { + mOrganizer.registerOrganizer(); + + verify(mTaskOrganizerController).registerTaskOrganizer(any(ITaskOrganizer.class)); } @Test diff --git a/location/java/android/location/timezone/LocationTimeZoneEvent.java b/location/java/android/location/timezone/LocationTimeZoneEvent.java index 540bdfffe16a..55bc507964e6 100644 --- a/location/java/android/location/timezone/LocationTimeZoneEvent.java +++ b/location/java/android/location/timezone/LocationTimeZoneEvent.java @@ -35,7 +35,8 @@ import java.util.Objects; */ public final class LocationTimeZoneEvent implements Parcelable { - @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_SUCCESS, EVENT_TYPE_SUCCESS }) + @IntDef({ EVENT_TYPE_UNKNOWN, EVENT_TYPE_PERMANENT_FAILURE, EVENT_TYPE_SUCCESS, + EVENT_TYPE_UNCERTAIN }) @interface EventType {} /** Uninitialized value for {@link #mEventType} - must not be used for real events. */ @@ -43,7 +44,7 @@ public final class LocationTimeZoneEvent implements Parcelable { /** * Indicates there was a permanent failure. This is not generally expected, and probably means a - * required backend service is no longer supported / available. + * required backend service has been turned down, or the client is unreasonably old. */ public static final int EVENT_TYPE_PERMANENT_FAILURE = 1; @@ -54,8 +55,9 @@ public final class LocationTimeZoneEvent implements Parcelable { public static final int EVENT_TYPE_SUCCESS = 2; /** - * Indicates the time zone is not known because there was a (temporary) error, e.g. when - * detecting location, or when resolving the location to a time zone. + * Indicates the time zone is not known because of an expected runtime state or error, e.g. when + * the provider is unable to detect location, or there was a problem when resolving the location + * to a time zone. */ public static final int EVENT_TYPE_UNCERTAIN = 3; diff --git a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml index 469ac91073f9..656e94ae348b 100644 --- a/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml +++ b/packages/CarSystemUI/res/drawable/hvac_decrease_button.xml @@ -27,20 +27,20 @@ android:width="@dimen/system_bar_icon_drawing_size" android:height="@dimen/system_bar_icon_drawing_size"/> <solid - android:color="#3C4043"/> + android:color="@color/hvac_temperature_adjust_button_color"/> </shape> </aapt:attr> </item> <item android:gravity="center" - android:width="48dp" - android:height="48dp"> + android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size"> <aapt:attr name="android:drawable"> - <vector android:width="48dp" - android:height="48dp" + <vector android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:fillColor="#8AB4F8" + android:fillColor="@color/hvac_temperature_decrease_arrow_color" android:pathData="M14,7l-5,5 5,5V7z"/> </vector> </aapt:attr> diff --git a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml index a3fca2233ddd..57c07c873d76 100644 --- a/packages/CarSystemUI/res/drawable/hvac_increase_button.xml +++ b/packages/CarSystemUI/res/drawable/hvac_increase_button.xml @@ -27,20 +27,20 @@ android:width="@dimen/system_bar_icon_drawing_size" android:height="@dimen/system_bar_icon_drawing_size"/> <solid - android:color="#3C4043"/> + android:color="@color/hvac_temperature_adjust_button_color"/> </shape> </aapt:attr> </item> <item android:gravity="center" - android:width="48dp" - android:height="48dp"> + android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size"> <aapt:attr name="android:drawable"> - <vector android:width="48dp" - android:height="48dp" + <vector android:width="@dimen/system_bar_icon_drawing_size" + android:height="@dimen/system_bar_icon_drawing_size" android:viewportWidth="24.0" android:viewportHeight="24.0"> <path - android:fillColor="#F28B82" + android:fillColor="@color/hvac_temperature_increase_arrow_color" android:pathData="M10,17l5,-5 -5,-5v10z"/> </vector> </aapt:attr> diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml index d9c149106451..b8ac2b43b047 100644 --- a/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml +++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar_unprovisioned.xml @@ -56,8 +56,6 @@ android:textAppearance="@style/TextAppearance.CarStatus" systemui:hvacAreaId="49" systemui:hvacPivotOffset="60dp" - systemui:hvacPropertyId="358614275" - systemui:hvacTempFormat="%.0f\u00B0" /> </FrameLayout> @@ -130,8 +128,6 @@ android:textAppearance="@style/TextAppearance.CarStatus" systemui:hvacAreaId="68" systemui:hvacPivotOffset="60dp" - systemui:hvacPropertyId="358614275" - systemui:hvacTempFormat="%.0f\u00B0" /> </FrameLayout> </RelativeLayout> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index 1e15affcbf48..c390cc8d70a4 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -37,6 +37,11 @@ <color name="status_bar_background_color">#33000000</color> <drawable name="system_bar_background">@color/status_bar_background_color</drawable> + <!-- colors for hvac temperature view --> + <color name="hvac_temperature_adjust_button_color">#3C4043</color> + <color name="hvac_temperature_decrease_arrow_color">#8AB4F8</color> + <color name="hvac_temperature_increase_arrow_color">#F28B82</color> + <!-- The background color of the notification shade --> <color name="notification_shade_background_color">#D6000000</color> diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index f02a8e7648c0..28b8eadf9750 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -48,8 +48,14 @@ <dimen name="system_bar_user_icon_padding">16dp</dimen> <dimen name="system_bar_user_icon_drawing_size">36dp</dimen> + <!-- Padding on either side of the group of all system bar buttons --> <dimen name="system_bar_button_group_padding">64dp</dimen> <dimen name="system_bar_icon_drawing_size">44dp</dimen> + <dimen name="system_bar_button_size">76dp</dimen> + <!-- Margin between the system bar buttons --> + <dimen name="system_bar_button_margin">32dp</dimen> + <!-- Padding between the system bar button and the icon within it --> + <dimen name="system_bar_button_padding">16dp</dimen> <!-- The amount by which to scale up the status bar icons. --> <item name="status_bar_icon_scale_factor" format="float" type="dimen">1.75</item> @@ -61,8 +67,8 @@ <dimen name="hvac_temperature_text_padding">8dp</dimen> <dimen name="hvac_temperature_button_size">76dp</dimen> <!--These values represent MIN and MAX for hvac--> - <item name="hvac_min_value_celsius" format="float" type="dimen">0</item> - <item name="hvac_max_value_celsius" format="float" type="dimen">126</item> + <item name="hvac_min_value_celsius" format="float" type="dimen">10</item> + <item name="hvac_max_value_celsius" format="float" type="dimen">35</item> <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or quick settings header --> diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml index 0db17ac42a77..f242db0aec09 100644 --- a/packages/CarSystemUI/res/values/styles.xml +++ b/packages/CarSystemUI/res/values/styles.xml @@ -43,10 +43,10 @@ </style> <style name="NavigationBarButton"> - <item name="android:layout_height">76dp</item> - <item name="android:layout_width">76dp</item> - <item name="android:layout_marginEnd">32dp</item> - <item name="android:padding">16dp</item> + <item name="android:layout_height">@dimen/system_bar_button_size</item> + <item name="android:layout_width">@dimen/system_bar_button_size</item> + <item name="android:layout_marginEnd">@dimen/system_bar_button_margin</item> + <item name="android:padding">@dimen/system_bar_button_padding</item> <item name="android:gravity">center</item> <item name="android:background">?android:attr/selectableItemBackground</item> </style> diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java index 4cac4456789d..85d4ceb81eeb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java @@ -35,22 +35,27 @@ import com.android.systemui.R; */ public class AdjustableTemperatureView extends LinearLayout implements TemperatureView { - private HvacController mHvacController; - private float mCurrentTempC; + private final int mAreaId; private TextView mTempTextView; + private float mMinTempC; + private float mMaxTempC; + private String mTempFormat; private boolean mDisplayInFahrenheit = false; - private final float mMinTempC; - private final float mMaxTempC; - private final int mAreaId; - private final String mTempFormat; + private HvacController mHvacController; + private float mCurrentTempC; public AdjustableTemperatureView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView); mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId, -1); + } - LayoutInflater.from(context).inflate(R.layout.adjustable_temperature_view, /* root= */this); + @Override + public void onFinishInflate() { + super.onFinishInflate(); + LayoutInflater.from(getContext()).inflate(R.layout.adjustable_temperature_view, + /* root= */ this); mTempFormat = getResources().getString(R.string.hvac_temperature_format); mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius); mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius); @@ -63,7 +68,7 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu } @Override - public void setTemperatureView(float tempC) { + public void setTemp(float tempC) { if (tempC > mMaxTempC || tempC < mMinTempC) { return; } @@ -78,7 +83,7 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu @Override public void setDisplayInFahrenheit(boolean displayFahrenheit) { mDisplayInFahrenheit = displayFahrenheit; - setTemperatureView(mCurrentTempC); + setTemp(mCurrentTempC); } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java index 567baa91cb59..b98b68038e6f 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AnimatedTemperatureView.java @@ -189,7 +189,7 @@ public class AnimatedTemperatureView extends FrameLayout implements TemperatureV * @param temp - The current temp or NaN */ @Override - public void setTemperatureView(float temp) { + public void setTemp(float temp) { if (mDisplayInFahrenheit) { temp = convertToFahrenheit(temp); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java index f7451dc6fdee..10a361c3084e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/HvacController.java @@ -30,6 +30,7 @@ import android.view.ViewGroup; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.UiBackground; import java.util.ArrayList; import java.util.HashMap; @@ -37,6 +38,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -49,6 +51,7 @@ public class HvacController { public static final String TAG = "HvacController"; private static final boolean DEBUG = true; + private final Executor mBackgroundExecutor; private final CarServiceProvider mCarServiceProvider; private final Set<TemperatureView> mRegisteredViews = new HashSet<>(); @@ -68,7 +71,7 @@ public class HvacController { Log.d(TAG, "onChangeEvent: " + areaId + ":" + value); } for (TemperatureView view : temperatureViews) { - view.setTemperatureView(newTemp); + view.setTemp(newTemp); } } } catch (Exception e) { @@ -117,8 +120,10 @@ public class HvacController { }; @Inject - public HvacController(CarServiceProvider carServiceProvider) { + public HvacController(CarServiceProvider carServiceProvider, + @UiBackground Executor backgroundExecutor) { mCarServiceProvider = carServiceProvider; + mBackgroundExecutor = backgroundExecutor; } /** @@ -171,14 +176,14 @@ public class HvacController { } if (mCarPropertyManager == null || !mCarPropertyManager.isPropertyAvailable( HVAC_TEMPERATURE_SET, zone)) { - view.setTemperatureView(Float.NaN); + view.setTemp(Float.NaN); return; } - view.setTemperatureView( + view.setTemp( mCarPropertyManager.getFloatProperty(HVAC_TEMPERATURE_SET, zone)); view.setHvacController(this); } catch (Exception e) { - view.setTemperatureView(Float.NaN); + view.setTemp(Float.NaN); Log.e(TAG, "Failed to get value from hvac service", e); } } @@ -213,7 +218,8 @@ public class HvacController { public void setTemperature(float tempC, int zone) { if (mCarPropertyManager != null) { // Internally, all temperatures are represented in floating point Celsius - mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC); + mBackgroundExecutor.execute( + () -> mCarPropertyManager.setFloatProperty(HVAC_TEMPERATURE_SET, zone, tempC)); } } @@ -234,6 +240,6 @@ public class HvacController { * @return Temperature in Celsius. */ public static float convertToCelsius(float tempF) { - return (float) ((tempF - 32) * 0.55555555556); + return (tempF - 32) * 5f / 9f; } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java index 252f7830b72c..90df15c907dd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureTextView.java @@ -56,7 +56,7 @@ public class TemperatureTextView extends TextView implements TemperatureView { * @param temp - The current temp or NaN */ @Override - public void setTemperatureView(float temp) { + public void setTemp(float temp) { if (Float.isNaN(temp)) { setText("--"); return; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java index 3c0e0acc446c..6edf25431ffd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/TemperatureView.java @@ -33,7 +33,7 @@ public interface TemperatureView { * * @param temp - The current temp in Celsius or NaN */ - void setTemperatureView(float temp); + void setTemp(float temp); /** * Render the displayed temperature in Fahrenheit diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java index e8850def6bcd..a3a55aae5f18 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java @@ -46,9 +46,12 @@ import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.concurrent.Executor; + @CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @@ -64,6 +67,8 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { private Car mCar; @Mock private CarPropertyManager mCarPropertyManager; + @Mock + private Executor mExecutor; @Before public void setUp() { @@ -72,9 +77,10 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, mExecutor); mHvacController.connectToCarService(); mAdjustableTemperatureView = new AdjustableTemperatureView(getContext(), /* attrs= */ null); + mAdjustableTemperatureView.onFinishInflate(); mAdjustableTemperatureView.setHvacController(mHvacController); } @@ -118,6 +124,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(TEMP_CELSIUS + 1)); } @@ -132,6 +141,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(TEMP_CELSIUS - 1)); } @@ -150,6 +162,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_increase_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) + 1))); } @@ -168,6 +183,9 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase { mAdjustableTemperatureView.findViewById(R.id.hvac_decrease_button).callOnClick(); + ArgumentCaptor<Runnable> setTempRunnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mExecutor).execute(setTempRunnableCaptor.capture()); + setTempRunnableCaptor.getValue().run(); verify(mCarPropertyManager).setFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt(), eq(convertToCelsius(convertToFahrenheit(TEMP_CELSIUS) - 1))); } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java index 9912657d78e1..52f07dfd6b81 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java @@ -40,6 +40,8 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.CarSystemUiTest; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -70,7 +72,8 @@ public class HvacControllerTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, + new FakeExecutor(new FakeSystemClock())); mHvacController.connectToCarService(); } @@ -86,31 +89,31 @@ public class HvacControllerTest extends SysuiTestCase { TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); } @Test public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() { TemperatureTextView v = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); resetTemperatureView(v, AREA_ID); mHvacController.addTemperatureViewToController(v); - verify(v, never()).setTemperatureView(TEMP); + verify(v, never()).setTemp(TEMP); } @Test public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() { TemperatureTextView v1 = setupMockTemperatureTextView(AREA_ID, TEMP); mHvacController.addTemperatureViewToController(v1); - verify(v1).setTemperatureView(TEMP); + verify(v1).setTemp(TEMP); TemperatureTextView v2 = setupMockTemperatureTextView( AREA_ID + 1, TEMP + 1); mHvacController.addTemperatureViewToController(v2); - verify(v2).setTemperatureView(TEMP + 1); + verify(v2).setTemp(TEMP + 1); } @Test @@ -124,7 +127,7 @@ public class HvacControllerTest extends SysuiTestCase { mHvacController.addTemperatureViewToController(v); verify(v).setDisplayInFahrenheit(true); - verify(v).setTemperatureView(TEMP); + verify(v).setTemp(TEMP); } private TemperatureTextView setupMockTemperatureTextView(int areaId, float value) { diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java index e97d9d9b3f6a..3ed811105a54 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/TemperatureTextViewTest.java @@ -40,6 +40,8 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.CarSystemUiTest; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -72,7 +74,8 @@ public class TemperatureTextViewTest extends SysuiTestCase { when(mCar.getCarManager(Car.PROPERTY_SERVICE)).thenReturn(mCarPropertyManager); CarServiceProvider carServiceProvider = new CarServiceProvider(mContext, mCar); - mHvacController = new HvacController(carServiceProvider); + mHvacController = new HvacController(carServiceProvider, + new FakeExecutor(new FakeSystemClock())); mHvacController.connectToCarService(); mTextView = new TemperatureTextView(getContext(), /* attrs= */ null); } diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index dcdadbdf3454..4a11aa77c7fc 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -400,7 +400,7 @@ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Aktibo. Aldatzeko, sakatu hau."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Egonean moduko aplikazioaren egoera: <xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Abian diren zerbitzuak"</string> - <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu unean abian diren zerbitzuak"</string> + <string name="runningservices_settings_summary" msgid="1046080643262665743">"Ikusi eta kontrolatu une honetan abian diren zerbitzuak"</string> <string name="select_webview_provider_title" msgid="3917815648099445503">"WebView inplementazioa"</string> <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Ezarri WebView inplementazioa"</string> <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Jada ez dago erabilgarri aukera hori. Saiatu berriro."</string> diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml index 743017c82e3a..7a4e71b18ec0 100644 --- a/packages/SettingsLib/res/values-ja/arrays.xml +++ b/packages/SettingsLib/res/values-ja/arrays.xml @@ -243,7 +243,7 @@ </string-array> <string-array name="track_frame_time_entries"> <item msgid="634406443901014984">"OFF"</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-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index c4b5f7e7477f..419c18f3b8c6 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -396,8 +396,8 @@ <item msgid="1282170165150762976">"Санарип мазмун үчүн оптималдаштырылган түстөр"</item> </string-array> <string name="inactive_apps_title" msgid="5372523625297212320">"Көшүү режиминдеги колдонмолор"</string> - <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Которуштуруу үчүн таптап коюңуз."</string> - <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Которуштуруу үчүн таптап коюңуз."</string> + <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Иштеген жок. Күйгүзүү үчүн басып коюңуз."</string> + <string name="inactive_app_active_summary" msgid="8047630990208722344">"Иштеп турат. Өчүрүү үчүн басып коюңуз."</string> <string name="standby_bucket_summary" msgid="5128193447550429600">"Көшүү режиминдеги колдонмонун абалы:<xliff:g id="BUCKET"> %s</xliff:g>"</string> <string name="runningservices_settings_title" msgid="6460099290493086515">"Иштеп жаткан кызматтар"</string> <string name="runningservices_settings_summary" msgid="1046080643262665743">"Учурда иштеп жаткан кызматтарды көрүп, көзөмөлдөп турасыз"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index fb7b63410a5f..58d4af1c2c64 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -204,10 +204,10 @@ <string name="tethering_settings_not_available" msgid="266821736434699780">"Поставките за спојување не се достапни за овој корисник"</string> <string name="apn_settings_not_available" msgid="1147111671403342300">"Поставките за името на пристапната точка не се достапни за овој корисник"</string> <string name="enable_adb" msgid="8072776357237289039">"Отстранување грешки на USB"</string> - <string name="enable_adb_summary" msgid="3711526030096574316">"Режим на отстранување грешки кога е поврзано USB"</string> + <string name="enable_adb_summary" msgid="3711526030096574316">"Режим за отстранување грешки кога е поврзано USB"</string> <string name="clear_adb_keys" msgid="3010148733140369917">"Отповикај овластувања за отстранување грешки од USB"</string> <string name="enable_adb_wireless" msgid="6973226350963971018">"Безжично отстранување грешки"</string> - <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим на отстранување грешки кога е поврзано Wi‑Fi"</string> + <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Режим за отстранување грешки кога е поврзано Wi‑Fi"</string> <string name="adb_wireless_error" msgid="721958772149779856">"Грешка"</string> <string name="adb_wireless_settings" msgid="2295017847215680229">"Безжично отстранување грешки"</string> <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"За да ги гледате и користите достапните уреди, вклучете го безжичното отстранување грешки"</string> diff --git a/packages/SystemUI/docs/camera.md b/packages/SystemUI/docs/camera.md new file mode 100644 index 000000000000..7a7a5aa3eb7f --- /dev/null +++ b/packages/SystemUI/docs/camera.md @@ -0,0 +1,33 @@ +# How double-click power launches the camera + +_as of august 2020_ + + +## Sequence of events + + + +1. [PhoneWindowManager.java](/services/core/java/com/android/server/policy/PhoneWindowManager.java) is responsible for all power button presses (see `interceptPowerKeyDown`). +2. Even though PWMgr has a lot of logic to detect all manner of power button multipresses and gestures, it also checks with GestureLauncherService, which is also [offered the chance](/services/core/java/com/android/server/policy/PhoneWindowManager.java#943) to [intercept](/services/core/java/com/android/server/GestureLauncherService.java#358) the power key. +3. GLS is responsible for the camera timeout, and if it detects one, it [forwards it to the StatusBarManagerService](/services/core/java/com/android/server/GestureLauncherService.java#475) (which hands it off to SystemUI). +4. Inside SystemUI, [onCameraLaunchDetected](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3927) looks at the keyguard state and determines + 1. whether the camera is even allowed + 2. whether the screen is on; if not, we need to delay until that happens + 3. whether the device is locked (defined as "keyuguard is showing"). +5. If the device is unlocked (no keyguard), the camera is launched immediately. [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3949). +6. If the keyguard is up, however, [KeyguardBottomAreaView.launchCamera](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#477) takes over to handle the "secure camera" (a different intent, usually directing to the same app, but giving that app the cue to not allow access to the photo roll, etc). +7. If the intent [would have to launch a resolver](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#480) (the user has multiple cameras installed and hasn’t chosen one to always launch for the `SECURE_CAMERA_INTENT`), + 1. In order to show the resolver, the lockscreen "bouncer" (authentication method) [is first presented](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523). +8. Otherwise (just one secure camera), [it is launched](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#501) (with some window animation gymnastics). + + +## Which intent launches? + + + +* If the keyguard is not showing (device is unlocked) + * `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT`, defined to be `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA`. + * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java#3950) in StatusBar.java. +* If the keyguard is showing (device locked) + * [KeyguardBottomAreaView.getCameraIntent()](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#366) is consulted, which allows the "keyguard right button" (which we don’t actually show) to control the camera intent. The [default implementation](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#831) returns one of `KeyguardBottomAreaView.INSECURE_CAMERA_INTENT` or `KeyguardBottomAreaView.SECURE_CAMERA_INTENT`, which are `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA` and `MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE`, respectively. + * [Callsite](/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java#523) in KeyguardBottomAreaView.java. diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 862405609de8..5793cddd7d26 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -57,7 +57,6 @@ import android.window.TaskOrganizer; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransactionCallback; -import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; import com.android.systemui.dagger.SysUISingleton; @@ -309,7 +308,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize // Don't bother doing an animation if the display rotation differs or if it's in // a non-supported windowing mode applyWindowingModeChangeOnExit(wct, direction); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); // Send finished callback though animation is ignored. sendOnPipTransitionFinished(direction); mInPip = false; @@ -379,7 +378,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize // Reset the task bounds first to ensure the activity configuration is reset as well final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mToken, null); - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); ActivityTaskManager.getService().removeStacksInWindowingModes( new int[]{ WINDOWING_MODE_PINNED }); @@ -932,7 +931,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements ShellTaskOrganize */ public void applyFinishBoundsResize(@NonNull WindowContainerTransaction wct, @PipAnimationController.TransitionDirection int direction) { - WindowOrganizer.applyTransaction(wct); + mTaskOrganizer.applyTransaction(wct); } /** diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index b9625397d237..16077cb6082f 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -228,7 +228,7 @@ public class FullRestoreEngine extends RestoreEngine { PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( mBackupManagerService.getPackageManager(), allowApks, info, signatures, - pmi, mUserId); + pmi, mUserId, mBackupEligibilityRules); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index 3789fa14e87b..6963248734a3 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -389,13 +389,29 @@ public class TarBackupReader { public RestorePolicy chooseRestorePolicy(PackageManager packageManager, boolean allowApks, FileMetadata info, Signature[] signatures, PackageManagerInternal pmi, int userId) { + return chooseRestorePolicy(packageManager, allowApks, info, signatures, pmi, userId, + BackupEligibilityRules.forBackup(packageManager, pmi, userId)); + } + + /** + * Chooses restore policy. + * + * @param packageManager - PackageManager instance. + * @param allowApks - allow restore set to include apks. + * @param info - file metadata. + * @param signatures - array of signatures parsed from backup file. + * @param userId - ID of the user for which restore is performed. + * @param eligibilityRules - {@link BackupEligibilityRules} for this operation. + * @return a restore policy constant. + */ + public RestorePolicy chooseRestorePolicy(PackageManager packageManager, + boolean allowApks, FileMetadata info, Signature[] signatures, + PackageManagerInternal pmi, int userId, BackupEligibilityRules eligibilityRules) { if (signatures == null) { return RestorePolicy.IGNORE; } RestorePolicy policy = RestorePolicy.IGNORE; - BackupEligibilityRules eligibilityRules = BackupEligibilityRules.forBackup(packageManager, - pmi, userId); // Okay, got the manifest info we need... try { PackageInfo pkgInfo = packageManager.getPackageInfoAsUser( diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index f372c6f85ec6..0d79240a4b59 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -166,6 +166,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private String mAddress; private String mName; private final ContentResolver mContentResolver; + private final int mUserId; private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks; private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks; private IBinder mBluetoothBinder; @@ -481,6 +482,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mName = null; mErrorRecoveryRetryCounter = 0; mContentResolver = context.getContentResolver(); + mUserId = mContentResolver.getUserId(); // Observe BLE scan only mode settings change. registerForBleScanModeChange(); mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); @@ -625,7 +627,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation) - && Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) + && Settings.Secure.getIntForUser(mContentResolver, + SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId) == 0) { // if the valid flag is not set, don't load the address and name if (DBG) { @@ -633,8 +636,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } return; } - mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME); - mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS); + mName = Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId); + mAddress = Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId); if (DBG) { Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress); } @@ -648,26 +653,31 @@ class BluetoothManagerService extends IBluetoothManager.Stub { */ private void storeNameAndAddress(String name, String address) { if (name != null) { - Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name); + Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name, + mUserId); mName = name; if (DBG) { - Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getString(mContentResolver, - SECURE_SETTINGS_BLUETOOTH_NAME)); + Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, + mUserId)); } } if (address != null) { - Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address); + Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, + address, mUserId); mAddress = address; if (DBG) { Slog.d(TAG, - "Stored Bluetoothaddress: " + Settings.Secure.getString(mContentResolver, - SECURE_SETTINGS_BLUETOOTH_ADDRESS)); + "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser( + mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, + mUserId)); } } if ((name != null) && (address != null)) { - Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1); + Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1, + mUserId); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 162bfee8848d..155af82289d4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -656,7 +656,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalArgumentException("Invalid install mode: " + params.mode); } - // If caller requested explicit location, sanity check it, otherwise + // If caller requested explicit location, validity check it, otherwise // resolve the best internal or adopted location. if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { if (!PackageHelper.fitsOnInternal(mContext, params)) { @@ -688,7 +688,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final int sessionId; final PackageInstallerSession session; synchronized (mSessions) { - // Sanity check that installer isn't going crazy + // Check that the installer does not have too many active sessions. final int activeCount = getSessionCount(mSessions, callingUid); if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) == PackageManager.PERMISSION_GRANTED) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 51164ba412b3..ca125320bbf2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -249,6 +249,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final PackageManagerService mPm; private final Handler mHandler; private final PackageSessionProvider mSessionProvider; + /** + * Note all calls must be done outside {@link #mLock} to prevent lock inversion. + */ private final StagingManager mStagingManager; final int sessionId; @@ -389,6 +392,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private String mStagedSessionErrorMessage; /** + * The callback to run when pre-reboot verification has ended. Used by {@link #abandonStaged()} + * to delay session clean-up until it is safe to do so. + */ + @GuardedBy("mLock") + @Nullable + private Runnable mPendingAbandonCallback; + /** + * {@code true} if pre-reboot verification is ongoing which means it is not safe for + * {@link #abandon()} to clean up staging directories. + */ + @GuardedBy("mLock") + private boolean mInPreRebootVerification; + + /** * Path to the validated base APK for this session, which may point at an * APK inside the session (when the session defines the base), or it may * point at the existing base APK (when adding splits to an existing app). @@ -978,7 +995,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private ParcelFileDescriptor doWriteInternal(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor incomingFd) throws IOException { - // Quick sanity check of state, and allocate a pipe for ourselves. We + // Quick validity check of state, and allocate a pipe for ourselves. We // then do heavy disk allocation outside the lock, but this open pipe // will block any attempted install transitions. final RevocableFileDescriptor fd; @@ -1454,26 +1471,54 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(patb): since the work done here for a parent session in a multi-package install is // mostly superficial, consider splitting this method for the parent and // single / child sessions. - synchronized (mLock) { - if (mCommitted) { - return true; + try { + synchronized (mLock) { + if (mCommitted) { + return true; + } + // Read transfers from the original owner stay open, but as the session's data + // cannot be modified anymore, there is no leak of information. For staged sessions, + // further validation is performed by the staging manager. + if (!params.isMultiPackage) { + if (!prepareDataLoaderLocked()) { + return false; + } + + if (isApexInstallation()) { + validateApexInstallLocked(); + } else { + validateApkInstallLocked(); + } + } } - if (!streamAndValidateLocked()) { - return false; + if (params.isStaged) { + mStagingManager.checkNonOverlappingWithStagedSessions(this); } - // Client staging is fully done at this point - mClientProgress = 1f; - computeProgressLocked(true); + synchronized (mLock) { + if (mDestroyed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session destroyed"); + } + // Client staging is fully done at this point + mClientProgress = 1f; + computeProgressLocked(true); - // This ongoing commit should keep session active, even though client - // will probably close their end. - mActiveCount.incrementAndGet(); + // This ongoing commit should keep session active, even though client + // will probably close their end. + mActiveCount.incrementAndGet(); - mCommitted = true; + mCommitted = true; + } + return true; + } catch (PackageManagerException e) { + throw onSessionValidationFailure(e); + } catch (Throwable e) { + // Convert all exceptions into package manager exceptions as only those are handled + // in the code above. + throw onSessionValidationFailure(new PackageManagerException(e)); } - return true; } @GuardedBy("mLock") @@ -1511,44 +1556,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - /** - * Prepare DataLoader and stream content for DataLoader sessions. - * Validate the contents of all session. - * - * @return false if the data loader could not be prepared. - * @throws PackageManagerException when an unrecoverable exception is encountered - */ - @GuardedBy("mLock") - private boolean streamAndValidateLocked() throws PackageManagerException { - try { - // Read transfers from the original owner stay open, but as the session's data cannot - // be modified anymore, there is no leak of information. For staged sessions, further - // validation is performed by the staging manager. - if (!params.isMultiPackage) { - if (!prepareDataLoaderLocked()) { - return false; - } - - if (isApexInstallation()) { - validateApexInstallLocked(); - } else { - validateApkInstallLocked(); - } - } - - if (params.isStaged) { - mStagingManager.checkNonOverlappingWithStagedSessions(this); - } - return true; - } catch (PackageManagerException e) { - throw onSessionValidationFailure(e); - } catch (Throwable e) { - // Convert all exceptions into package manager exceptions as only those are handled - // in the code above. - throw onSessionValidationFailure(new PackageManagerException(e)); - } - } - private PackageManagerException onSessionValidationFailure(PackageManagerException e) { onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); return e; @@ -1571,7 +1578,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode); // TODO(b/136257624): Remove this once all verification logic has been transferred out // of StagingManager. - mStagingManager.notifyVerificationComplete(sessionId); + mStagingManager.notifyVerificationComplete(this); } else { // Dispatch message to remove session from PackageInstallerService. dispatchSessionFinished(error, msg, null); @@ -1837,21 +1844,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throws PackageManagerException { assertNotLocked("makeSessionActive"); - synchronized (mLock) { - if (mRelinquished) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session relinquished"); - } - if (mDestroyed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session destroyed"); - } - if (!mSealed) { - throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, - "Session not sealed"); - } - } - // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc if (!params.isMultiPackage && needToAskForPermissions()) { // User needs to confirm installation; @@ -1881,6 +1873,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private PackageManagerService.VerificationParams makeVerificationParamsLocked() throws PackageManagerException { + if (mRelinquished) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session relinquished"); + } + if (mDestroyed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session destroyed"); + } + if (!mSealed) { + throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, + "Session not sealed"); + } + // TODO(b/136257624): Some logic in this if block probably belongs in // makeInstallParams(). if (!params.isMultiPackage && !isApexInstallation()) { @@ -2787,14 +2792,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void abandonStaged() { + final Runnable r; synchronized (mLock) { - if (mDestroyed) { - // If a user abandons staged session in an unsafe state, then system will try to - // abandon the destroyed staged session when it is safe on behalf of the user. - assertCallerIsOwnerOrRootOrSystemLocked(); - } else { - assertCallerIsOwnerOrRootLocked(); - } + assertCallerIsOwnerOrRootLocked(); if (isStagedAndInTerminalState()) { // We keep the session in the database if it's in a finalized state. It will be // removed by PackageInstallerService when the last update time is old enough. @@ -2803,17 +2803,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } mDestroyed = true; - if (mCommitted) { - if (!mStagingManager.abortCommittedSessionLocked(this)) { - // Do not clean up the staged session from system. It is not safe yet. - mCallback.onStagedSessionChanged(this); - return; + boolean isCommitted = mCommitted; + List<PackageInstallerSession> childSessions = getChildSessionsLocked(); + r = () -> { + assertNotLocked("abandonStaged"); + if (isCommitted) { + mStagingManager.abortCommittedSession(this); } + cleanStageDir(childSessions); + destroyInternal(); + dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + }; + if (mInPreRebootVerification) { + // Pre-reboot verification is ongoing. It is not safe to clean up the session yet. + mPendingAbandonCallback = r; + mCallback.onStagedSessionChanged(this); + return; } - cleanStageDir(getChildSessionsLocked()); - destroyInternal(); } - dispatchSessionFinished(INSTALL_FAILED_ABORTED, "Session was abandoned", null); + r.run(); } @Override @@ -2830,6 +2838,50 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** + * Notified by the staging manager that pre-reboot verification is about to start. The return + * value should be checked to decide whether it is OK to start pre-reboot verification. In + * the case of a destroyed session, {@code false} is returned and there is no need to start + * pre-reboot verification. + */ + boolean notifyStagedStartPreRebootVerification() { + synchronized (mLock) { + if (mInPreRebootVerification) { + throw new IllegalStateException("Pre-reboot verification has started"); + } + if (mDestroyed) { + return false; + } + mInPreRebootVerification = true; + return true; + } + } + + private void dispatchPendingAbandonCallback() { + final Runnable callback; + synchronized (mLock) { + callback = mPendingAbandonCallback; + mPendingAbandonCallback = null; + } + if (callback != null) { + callback.run(); + } + } + + /** + * Notified by the staging manager that pre-reboot verification has ended. Now it is safe to + * clean up the session if {@link #abandon()} has been called previously. + */ + void notifyStagedEndPreRebootVerification() { + synchronized (mLock) { + if (!mInPreRebootVerification) { + throw new IllegalStateException("Pre-reboot verification not started"); + } + mInPreRebootVerification = false; + } + dispatchPendingAbandonCallback(); + } + @Override public boolean isMultiPackage() { return params.isMultiPackage; @@ -3744,7 +3796,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { out.endTag(null, TAG_SESSION); } - // Sanity check to be performed when the session is restored from an external file. Only one + // Validity check to be performed when the session is restored from an external file. Only one // of the session states should be true, or none of them. private static boolean isStagedSessionStateValid(boolean isReady, boolean isApplied, boolean isFailed) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java index 3614cc047bf8..2bbca79741bd 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java @@ -67,7 +67,6 @@ public class PackageManagerShellCommandDataLoader extends DataLoaderService { } } - // Sanity check. if (sShellCommands.size() > TOO_MANY_PENDING_SHELL_COMMANDS) { Slog.e(TAG, "Too many pending shell commands: " + sShellCommands.size()); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 0c4eaec32ba5..462b21535371 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -60,7 +60,6 @@ import android.util.ArraySet; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; -import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; @@ -1028,22 +1027,12 @@ public class StagingManager { /** * <p>Abort committed staged session - * - * <p>This method must be called while holding {@link PackageInstallerSession#mLock}. - * - * <p>The method returns {@code false} to indicate it is not safe to clean up the session from - * system yet. When it is safe, the method returns {@code true}. - * - * <p> When it is safe to clean up, {@link StagingManager} will call - * {@link PackageInstallerSession#abandon()} on the session again. - * - * @return {@code true} if it is safe to cleanup the session resources, otherwise {@code false}. */ - boolean abortCommittedSessionLocked(@NonNull PackageInstallerSession session) { + void abortCommittedSession(@NonNull PackageInstallerSession session) { int sessionId = session.sessionId; - if (session.isStagedSessionApplied()) { - Slog.w(TAG, "Cannot abort applied session : " + sessionId); - return false; + if (session.isStagedAndInTerminalState()) { + Slog.w(TAG, "Cannot abort session in final state: " + sessionId); + return; } if (!session.isDestroyed()) { throw new IllegalStateException("Committed session must be destroyed before aborting it" @@ -1051,15 +1040,7 @@ public class StagingManager { } if (getStagedSession(sessionId) == null) { Slog.w(TAG, "Session " + sessionId + " has been abandoned already"); - return false; - } - - // If pre-reboot verification is running, then return false. StagingManager will call - // abandon again when pre-reboot verification ends. - if (mPreRebootVerificationHandler.isVerificationRunning(sessionId)) { - Slog.w(TAG, "Session " + sessionId + " aborted before pre-reboot " - + "verification completed."); - return false; + return; } // A session could be marked ready once its pre-reboot verification ends @@ -1075,7 +1056,6 @@ public class StagingManager { // Session was successfully aborted from apexd (if required) and pre-reboot verification // is also complete. It is now safe to clean up the session from system. abortSession(session); - return true; } /** @@ -1264,8 +1244,8 @@ public class StagingManager { // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all // verification logic is extracted out of StagingManager into PMS, we can remove // this. - void notifyVerificationComplete(int sessionId) { - mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId); + void notifyVerificationComplete(PackageInstallerSession session) { + mPreRebootVerificationHandler.onPreRebootVerificationComplete(session); } // TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all @@ -1279,8 +1259,6 @@ public class StagingManager { // Hold session ids before handler gets ready to do the verification. private IntArray mPendingSessionIds; private boolean mIsReady; - @GuardedBy("mVerificationRunning") - private final SparseBooleanArray mVerificationRunning = new SparseBooleanArray(); PreRebootVerificationHandler(Looper looper) { super(looper); @@ -1316,7 +1294,7 @@ public class StagingManager { } if (session.isDestroyed() || session.isStagedSessionFailed()) { // No point in running verification on a destroyed/failed session - onPreRebootVerificationComplete(sessionId); + onPreRebootVerificationComplete(session); return; } switch (msg.what) { @@ -1357,15 +1335,10 @@ public class StagingManager { } PackageInstallerSession session = getStagedSession(sessionId); - synchronized (mVerificationRunning) { - // Do not start verification on a session that has been abandoned - if (session == null || session.isDestroyed()) { - return; - } + if (session != null && session.notifyStagedStartPreRebootVerification()) { Slog.d(TAG, "Starting preRebootVerification for session " + sessionId); - mVerificationRunning.put(sessionId, true); + obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } - obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget(); } private void onPreRebootVerificationFailure(PackageInstallerSession session, @@ -1376,28 +1349,14 @@ public class StagingManager { // failed on next step and staging directory for session will be deleted. } session.setStagedSessionFailed(errorCode, errorMessage); - onPreRebootVerificationComplete(session.sessionId); + onPreRebootVerificationComplete(session); } // Things to do when pre-reboot verification completes for a particular sessionId - private void onPreRebootVerificationComplete(int sessionId) { - // Remove it from mVerificationRunning so that verification is considered complete - synchronized (mVerificationRunning) { - Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId); - mVerificationRunning.delete(sessionId); - } - // Check if the session was destroyed while pre-reboot verification was running. If so, - // abandon it again. - PackageInstallerSession session = getStagedSession(sessionId); - if (session != null && session.isDestroyed()) { - session.abandon(); - } - } - - private boolean isVerificationRunning(int sessionId) { - synchronized (mVerificationRunning) { - return mVerificationRunning.get(sessionId); - } + private void onPreRebootVerificationComplete(PackageInstallerSession session) { + int sessionId = session.sessionId; + Slog.d(TAG, "Stopping preRebootVerification for session " + sessionId); + session.notifyStagedEndPreRebootVerification(); } private void notifyPreRebootVerification_Start_Complete(int sessionId) { @@ -1516,7 +1475,7 @@ public class StagingManager { // or activate its apex, there won't be any files to work with as they will be cleaned // up by the system as part of abandonment. If session is abandoned before this point, // then the session is already destroyed and cannot be marked ready anymore. - onPreRebootVerificationComplete(session.sessionId); + onPreRebootVerificationComplete(session); // Proactively mark session as ready before calling apexd. Although this call order // looks counter-intuitive, this is the easiest way to ensure that session won't end up diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index ae2b040d0a89..e1cd9e334f4c 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -31,6 +31,7 @@ import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -242,8 +243,9 @@ public final class PermissionPolicyService extends SystemService { public void onReceive(Context context, Intent intent) { boolean hasSetupRun = true; try { - hasSetupRun = Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE) != 0; + final ContentResolver cr = getContext().getContentResolver(); + hasSetupRun = Settings.Secure.getIntForUser(cr, + Settings.Secure.USER_SETUP_COMPLETE, cr.getUserId()) != 0; } catch (Settings.SettingNotFoundException e) { // Ignore error, assume setup has run } diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index aee3d8d3499b..b68c54fc6365 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.timezonedetector.TimeZoneCapabilities; import android.app.timezonedetector.TimeZoneConfiguration; +import android.os.UserHandle; import java.util.Objects; @@ -56,6 +57,12 @@ public final class ConfigurationInternal { return mUserId; } + /** Returns the handle of the user this configuration is associated with. */ + @NonNull + public UserHandle getUserHandle() { + return UserHandle.of(mUserId); + } + /** Returns true if the user allowed to modify time zone configuration. */ public boolean isUserConfigAllowed() { return mUserConfigAllowed; @@ -198,13 +205,13 @@ public final class ConfigurationInternal { @Override public String toString() { - return "TimeZoneDetectorConfiguration{" + return "ConfigurationInternal{" + "mUserId=" + mUserId - + "mUserConfigAllowed=" + mUserConfigAllowed - + "mAutoDetectionSupported=" + mAutoDetectionSupported - + "mAutoDetectionEnabled=" + mAutoDetectionEnabled - + "mLocationEnabled=" + mLocationEnabled - + "mGeoDetectionEnabled=" + mGeoDetectionEnabled + + ", mUserConfigAllowed=" + mUserConfigAllowed + + ", mAutoDetectionSupported=" + mAutoDetectionSupported + + ", mAutoDetectionEnabled=" + mAutoDetectionEnabled + + ", mLocationEnabled=" + mLocationEnabled + + ", mGeoDetectionEnabled=" + mGeoDetectionEnabled + '}'; } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index 3230ef192b4b..a8d5c0282025 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -23,7 +23,7 @@ import java.io.PrintWriter; import java.util.function.Consumer; import java.util.function.Supplier; -/** Implemented the shell command interface for {@link TimeZoneDetectorService}. */ +/** Implements the shell command interface for {@link TimeZoneDetectorService}. */ class TimeZoneDetectorShellCommand extends ShellCommand { private final TimeZoneDetectorService mInterface; diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 63a595e3bc17..d9290fb18f08 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -38,7 +38,6 @@ import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; -import android.util.SparseBooleanArray; import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITaskOrganizerController; @@ -54,7 +53,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Set; import java.util.WeakHashMap; import java.util.function.Consumer; diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java new file mode 100644 index 000000000000..7049efa1cc2f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TestState.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.timezonedetector; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; + +/** + * A test support class used for tracking a piece of state in test objects like fakes and mocks. + * State can optionally be initialized using {@link #init}, which sets the value to an initial + * value, but is not treated as a change. Calls to {@link #set} are tracked and can be checked for + * during tests. The change-tracking can be cleared by calling {@link #commitLatest}, which puts the + * object into an unchanged state and sets the initial value to the latest value passed to + * {@link #set}. + */ +public class TestState<T> { + private T mInitialValue; + private final ArrayList<T> mValues = new ArrayList<>(5); + + /** Sets the initial value for the state. */ + public void init(T value) { + mValues.clear(); + mInitialValue = value; + } + + /** Sets the latest value for the state. */ + public void set(T value) { + mValues.add(value); + } + + /** Returns {@code true} if {@link #set} has been called. */ + public boolean hasBeenSet() { + return mValues.size() > 0; + } + + /** Fails if {@link #set} has been called. */ + public void assertHasNotBeenSet() { + assertFalse(hasBeenSet()); + } + + /** Fails if {@link #set} has not been called. */ + public void assertHasBeenSet() { + assertTrue(hasBeenSet()); + } + + /** + * Clears tracked changes and re-initializes using the latest set value as the initial value. + */ + public void commitLatest() { + if (hasBeenSet()) { + mInitialValue = mValues.get(mValues.size() - 1); + mValues.clear(); + } + } + + /** Asserts the latest value passed to {@link #set} equals {@code expected}. */ + public void assertLatestEquals(T expected) { + assertEquals(expected, getLatest()); + } + + /** Asserts the number of times {@link #set} has been called. */ + public void assertChangeCount(int expectedCount) { + assertEquals(expectedCount, mValues.size()); + } + + /** + * Returns the latest value passed to {@link #set}. If {@link #set} hasn't been called then the + * initial value is returned. + */ + public T getLatest() { + if (hasBeenSet()) { + return mValues.get(mValues.size() - 1); + } + return mInitialValue; + } +} diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index 2bee5e5e7295..1cdf19319209 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -54,7 +54,6 @@ import org.junit.Test; import java.io.StringWriter; import java.util.Arrays; import java.util.Collections; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -994,55 +993,6 @@ public class TimeZoneDetectorStrategyImplTest { } } - /** Some piece of state that tests want to track. */ - private static class TestState<T> { - private T mInitialValue; - private LinkedList<T> mValues = new LinkedList<>(); - - void init(T value) { - mValues.clear(); - mInitialValue = value; - } - - void set(T value) { - mValues.addFirst(value); - } - - boolean hasBeenSet() { - return mValues.size() > 0; - } - - void assertHasNotBeenSet() { - assertFalse(hasBeenSet()); - } - - void assertHasBeenSet() { - assertTrue(hasBeenSet()); - } - - void commitLatest() { - if (hasBeenSet()) { - mInitialValue = mValues.getLast(); - mValues.clear(); - } - } - - void assertLatestEquals(T expected) { - assertEquals(expected, getLatest()); - } - - void assertChangeCount(int expectedCount) { - assertEquals(expectedCount, mValues.size()); - } - - public T getLatest() { - if (hasBeenSet()) { - return mValues.getFirst(); - } - return mInitialValue; - } - } - /** * A "fluent" class allows reuse of code in tests: initialization, simulation and verification * logic. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 4ce9cb90b684..969016b1c017 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5555,7 +5555,8 @@ public class TelephonyManager { * @param events The telephony state(s) of interest to the listener, * as a bitwise-OR combination of {@link PhoneStateListener} * LISTEN_ flags. - * @deprecated use {@link #listen(long, PhoneStateListener) instead. + * @deprecated use {@link #listen(long, PhoneStateListener) instead due to the event number + * limit increased to 64. */ @Deprecated public void listen(PhoneStateListener listener, int events) { @@ -5563,9 +5564,6 @@ public class TelephonyManager { } /** - * Since the limit of {@link PhoneStateListener} LISTEN_ flags is exceeded, use long type to - * extend it. - * * Registers a listener object to receive notification of changes * in specified telephony states. * <p> diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 1588bf72c969..79f61bb791f6 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -2509,7 +2509,18 @@ public class WifiConfiguration implements Parcelable { @KeyMgmt.KeyMgmtScheme public int getAuthType() { if (allowedKeyManagement.cardinality() > 1) { - throw new IllegalStateException("More than one auth type set"); + if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) { + if (allowedKeyManagement.cardinality() == 2 + && allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { + return KeyMgmt.WPA_EAP; + } + if (allowedKeyManagement.cardinality() == 3 + && allowedKeyManagement.get(KeyMgmt.IEEE8021X) + && allowedKeyManagement.get(KeyMgmt.SUITE_B_192)) { + return KeyMgmt.SUITE_B_192; + } + } + throw new IllegalStateException("Invalid auth type set: " + allowedKeyManagement); } if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) { return KeyMgmt.WPA_PSK; diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index a7b6765e886a..62220a6237b1 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -22,6 +22,7 @@ import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_CERT; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK; import static org.junit.Assert.assertArrayEquals; @@ -537,4 +538,52 @@ public class WifiConfigurationTest { configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); assertFalse(configuration.needsPreSharedKey()); } + + @Test + public void testGetAuthType() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + assertEquals(KeyMgmt.WPA_PSK, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_SAE); + assertEquals(KeyMgmt.SAE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK); + assertEquals(KeyMgmt.WAPI_PSK, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_OPEN); + assertEquals(KeyMgmt.NONE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_OWE); + assertEquals(KeyMgmt.OWE, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP); + assertEquals(KeyMgmt.WPA_EAP, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); + assertEquals(KeyMgmt.SUITE_B_192, configuration.getAuthType()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_CERT); + assertEquals(KeyMgmt.WAPI_CERT, configuration.getAuthType()); + } + + @Test (expected = IllegalStateException.class) + public void testGetAuthTypeFailure1() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + configuration.getAuthType(); + } + + @Test (expected = IllegalStateException.class) + public void testGetAuthTypeFailure2() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.allowedKeyManagement.set(KeyMgmt.IEEE8021X); + configuration.allowedKeyManagement.set(KeyMgmt.WPA_EAP); + configuration.allowedKeyManagement.set(KeyMgmt.SAE); + configuration.getAuthType(); + } } |