diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java index bb9f13f1712c5c7d2430dbacab9dc221ffac5df5..5cebf8d91cfc40664720bda9b8dd3fcf447d9ad5 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java @@ -128,7 +128,7 @@ class BlobStoreConfig { */ public static final String KEY_USE_REVOCABLE_FD_FOR_READS = "use_revocable_fd_for_reads"; - public static final boolean DEFAULT_USE_REVOCABLE_FD_FOR_READS = true; + public static final boolean DEFAULT_USE_REVOCABLE_FD_FOR_READS = false; public static boolean USE_REVOCABLE_FD_FOR_READS = DEFAULT_USE_REVOCABLE_FD_FOR_READS; diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 0cadbfd23dbad2c8a60a7271d94abab6f75e9e62..36ccaf9c6fb8c29bc059a191e94b80fd8ba5cef2 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -455,9 +455,6 @@ public class AppStandbyController implements AppStandbyInternal { mSystemServicesReady = true; - // Offload to handler thread to avoid boot time impact. - mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); - boolean userFileExists; synchronized (mAppIdleLock) { userFileExists = mAppIdleHistory.userFileExists(UserHandle.USER_SYSTEM); @@ -474,7 +471,9 @@ public class AppStandbyController implements AppStandbyInternal { setChargingState(mInjector.isCharging()); // Offload to handler thread after boot completed to avoid boot time impact. This means - // that headless system apps may be put in a lower bucket until boot has completed. + // that app standby buckets may be slightly out of date and headless system apps may be + // put in a lower bucket until boot has completed. + mHandler.post(AppStandbyController.this::updatePowerWhitelistCache); mHandler.post(this::loadHeadlessSystemAppCache); } } @@ -1121,6 +1120,10 @@ public class AppStandbyController implements AppStandbyInternal { if (isDeviceProvisioningPackage(packageName)) { return STANDBY_BUCKET_EXEMPTED; } + + if (mInjector.isWellbeingPackage(packageName)) { + return STANDBY_BUCKET_WORKING_SET; + } } // Check this last, as it can be the most expensive check @@ -1930,6 +1933,7 @@ public class AppStandbyController implements AppStandbyInternal { */ @GuardedBy("mPowerWhitelistedApps") private final ArraySet mPowerWhitelistedApps = new ArraySet<>(); + private String mWellbeingApp = null; Injector(Context context, Looper looper) { mContext = context; @@ -1963,6 +1967,9 @@ public class AppStandbyController implements AppStandbyInternal { if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; } + + final PackageManager packageManager = mContext.getPackageManager(); + mWellbeingApp = packageManager.getWellbeingPackageName(); } mBootPhase = phase; } @@ -2007,6 +2014,14 @@ public class AppStandbyController implements AppStandbyInternal { } } + /** + * Returns {@code true} if the supplied package is the wellbeing app. Otherwise, + * returns {@code false}. + */ + boolean isWellbeingPackage(String packageName) { + return mWellbeingApp != null && mWellbeingApp.equals(packageName); + } + void updatePowerWhitelistCache() { try { // Don't call out to DeviceIdleController with the lock held. diff --git a/apex/permission/apex_manifest.json b/apex/permission/apex_manifest.json index ab57930341fa998af44936f43b7af722fcff2639..7960598affa364da0d6b3a9d14cd245f4c9a3aea 100644 --- a/apex/permission/apex_manifest.json +++ b/apex/permission/apex_manifest.json @@ -1,4 +1,4 @@ { "name": "com.android.permission", - "version": 300900700 + "version": 300000000 } diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index dc1612575f3829c67bed70ef66517a6f4e477601..13bf197aa9dcb8e55f7e34e4ea9b831eafb11078 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -554,6 +554,10 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector CREATOR; } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 660328f019bfa6186b463dc4e317707600d61465..feadd06761f9b850aeb88aa722d5bf23a4a72fdf 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -36,6 +36,7 @@ package android { public static final class R.bool { field public static final int config_assistantOnTopOfDream = 17891333; // 0x1110005 field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004 + field public static final int config_remoteInsetsControllerControlsSystemBars = 17891334; // 0x1110006 } public static final class R.string { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 5428730c168e1588b5a1031feb216c6d2ebda6d9..23787ebffefb7067711b2521025e57f95f1e9dbd 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3251,12 +3251,6 @@ public final class ActivityThread extends ClientTransactionHandler { sendMessage(H.CLEAN_UP_CONTEXT, cci); } - @Override - public void handleFixedRotationAdjustments(@NonNull IBinder token, - @Nullable FixedRotationAdjustments fixedRotationAdjustments) { - handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */); - } - /** * Applies the rotation adjustments to override display information in resources belong to the * provided token. If the token is activity token, the adjustments also apply to application @@ -3266,51 +3260,39 @@ public final class ActivityThread extends ClientTransactionHandler { * @param fixedRotationAdjustments The information to override the display adjustments of * corresponding resources. If it is null, the exiting override * will be cleared. - * @param overrideConfig The override configuration of activity. It is used to override - * application configuration. If it is non-null, it means the token is - * confirmed as activity token. Especially when launching new activity, - * {@link #mActivities} hasn't put the new token. */ - private void handleFixedRotationAdjustments(@NonNull IBinder token, - @Nullable FixedRotationAdjustments fixedRotationAdjustments, - @Nullable Configuration overrideConfig) { - // The element of application configuration override is set only if the application - // adjustments are needed, because activity already has its own override configuration. - final Configuration[] appConfigOverride; - final Consumer override; - if (fixedRotationAdjustments != null) { - appConfigOverride = new Configuration[1]; - override = displayAdjustments -> { - displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments); - if (appConfigOverride[0] != null) { - displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]); - } - }; - } else { - appConfigOverride = null; - override = null; - } + @Override + public void handleFixedRotationAdjustments(@NonNull IBinder token, + @Nullable FixedRotationAdjustments fixedRotationAdjustments) { + final Consumer override = fixedRotationAdjustments != null + ? displayAdjustments -> displayAdjustments + .setFixedRotationAdjustments(fixedRotationAdjustments) + : null; if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) { // No resources are associated with the token. return; } - if (overrideConfig == null) { - final ActivityClientRecord r = mActivities.get(token); - if (r == null) { - // It is not an activity token. Nothing to do for application. - return; - } - overrideConfig = r.overrideConfig; - } - if (appConfigOverride != null) { - appConfigOverride[0] = overrideConfig; + if (mActivities.get(token) == null) { + // Nothing to do for application if it is not an activity token. + return; } - // Apply the last override to application resources for compatibility. Because the Resources - // of Display can be from application, e.g. - // applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId) - // and the deprecated usage: - // applicationContext.getSystemService(WindowManager.class).getDefaultDisplay(); + overrideApplicationDisplayAdjustments(token, override); + } + + /** + * Applies the last override to application resources for compatibility. Because the Resources + * of Display can be from application, e.g. + * applicationContext.getSystemService(DisplayManager.class).getDisplay(displayId) + * and the deprecated usage: + * applicationContext.getSystemService(WindowManager.class).getDefaultDisplay(); + * + * @param token The owner and target of the override. + * @param override The display adjustments override for application resources. If it is null, + * the override of the token will be removed and pop the last one to use. + */ + private void overrideApplicationDisplayAdjustments(@NonNull IBinder token, + @Nullable Consumer override) { final Consumer appOverride; if (mActiveRotationAdjustments == null) { mActiveRotationAdjustments = new ArrayList<>(2); @@ -3543,8 +3525,13 @@ public final class ActivityThread extends ClientTransactionHandler { // The rotation adjustments must be applied before creating the activity, so the activity // can get the adjusted display info during creation. if (r.mPendingFixedRotationAdjustments != null) { - handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments, - r.overrideConfig); + // The adjustments should have been set by handleLaunchActivity, so the last one is the + // override for activity resources. + if (mActiveRotationAdjustments != null && !mActiveRotationAdjustments.isEmpty()) { + mResourcesManager.overrideTokenDisplayAdjustments(r.token, + mActiveRotationAdjustments.get( + mActiveRotationAdjustments.size() - 1).second); + } r.mPendingFixedRotationAdjustments = null; } @@ -3583,6 +3570,13 @@ public final class ActivityThread extends ClientTransactionHandler { mProfiler.startProfiling(); } + if (r.mPendingFixedRotationAdjustments != null) { + // The rotation adjustments must be applied before handling configuration, so process + // level display metrics can be adjusted. + overrideApplicationDisplayAdjustments(r.token, adjustments -> + adjustments.setFixedRotationAdjustments(r.mPendingFixedRotationAdjustments)); + } + // Make sure we are running with the most recent config. handleConfigurationChanged(null, null); @@ -5113,6 +5107,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } r.setState(ON_DESTROY); + mLastReportedWindowingMode.remove(r.activity.getActivityToken()); } schedulePurgeIdler(); // updatePendingActivityConfiguration() reads from mActivities to update @@ -5777,7 +5772,15 @@ public final class ActivityThread extends ClientTransactionHandler { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: " + config); - mResourcesManager.applyConfigurationToResourcesLocked(config, compat); + final Resources appResources = mInitialApplication.getResources(); + if (appResources.hasOverrideDisplayAdjustments()) { + // The value of Display#getRealSize will be adjusted by FixedRotationAdjustments, + // but Display#getSize refers to DisplayAdjustments#mConfiguration. So the rotated + // configuration also needs to set to the adjustments for consistency. + appResources.getDisplayAdjustments().getConfiguration().updateFrom(config); + } + mResourcesManager.applyConfigurationToResourcesLocked(config, compat, + appResources.getDisplayAdjustments()); updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), mResourcesManager.getConfiguration().getLocales()); @@ -7393,7 +7396,8 @@ public final class ActivityThread extends ClientTransactionHandler { // We need to apply this change to the resources immediately, because upon returning // the view hierarchy will be informed about it. if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig, - null /* compat */)) { + null /* compat */, + mInitialApplication.getResources().getDisplayAdjustments())) { updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(), mResourcesManager.getConfiguration().getLocales()); diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 92b0da1c761f56693691d166ebedeef7ce7c41c0..098d090b5e30d889b5a3522dca380a90a21ef380 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -105,7 +105,8 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd public ActivityView( @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay) { - this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false); + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + false /* disableSurfaceViewBackgroundLayer */); } /** @hide */ @@ -113,12 +114,22 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay, boolean disableSurfaceViewBackgroundLayer) { + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + disableSurfaceViewBackgroundLayer, false /* useTrustedDisplay */); + } + + // TODO(b/162901735): Refactor ActivityView with Builder + /** @hide */ + public ActivityView( + @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean disableSurfaceViewBackgroundLayer, boolean useTrustedDisplay) { super(context, attrs, defStyle); if (useTaskOrganizer()) { mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this); } else { mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance, - usePublicVirtualDisplay); + usePublicVirtualDisplay, useTrustedDisplay); } mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer); // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index c4f13fe0c2a68779e043e4f3d007a5e1af8c40e7..31ab2248236d0080eb30dc6e4b3a6cd41ff2b043 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1114,28 +1114,30 @@ public class AppOpsManager { public static final int OP_NO_ISOLATED_STORAGE = AppProtoEnums.APP_OP_NO_ISOLATED_STORAGE; /** - * Reserved key for 100 + * Phone call is using microphone * * @hide */ - public static final int OP_RESERVED_100 = 100; - + // TODO: Add as AppProtoEnums + public static final int OP_PHONE_CALL_MICROPHONE = 100; /** - * Reserved key for 101 + * Phone call is using camera * * @hide */ - public static final int OP_RESERVED_101 = 101; + // TODO: Add as AppProtoEnums + public static final int OP_PHONE_CALL_CAMERA = 101; /** - * Reserved key for 102 + * Audio is being recorded for hotword detection. * * @hide */ - public static final int OP_RESERVED_102 = 102; + // TODO: Add as AppProtoEnums + public static final int OP_RECORD_AUDIO_HOTWORD = 102; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public static final int _NUM_OP = 104; /** Access to coarse location information. */ @@ -1464,25 +1466,24 @@ public class AppOpsManager { public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage"; /** - * Reserved for 100 + * Phone call is using microphone * * @hide */ - public static final String OPSTR_RESERVED_100 = "android:opstr_reserved_100"; - + public static final String OPSTR_PHONE_CALL_MICROPHONE = "android:phone_call_microphone"; /** - * Reserved for 101 + * Phone call is using camera * * @hide */ - public static final String OPSTR_RESERVED_101 = "android:opstr_reserved_101"; + public static final String OPSTR_PHONE_CALL_CAMERA = "android:phone_call_camera"; /** - * Reserved for 102 + * Audio is being recorded for hotword detection. * * @hide */ - public static final String OPSTR_RESERVED_102 = "android:opstr_reserved_102"; + public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword"; /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; @@ -1674,9 +1675,9 @@ public class AppOpsManager { OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER OP_NO_ISOLATED_STORAGE, // NO_ISOLATED_STORAGE - OP_RESERVED_100, // OP_RESERVED_100 - OP_RESERVED_101, // OP_RESERVED_101 - OP_RESERVED_102, // OP_RESERVED_102 + OP_PHONE_CALL_MICROPHONE, // OP_PHONE_CALL_MICROPHONE + OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA + OP_RECORD_AUDIO_HOTWORD, // RECORD_AUDIO_HOTWORD OP_MANAGE_ONGOING_CALLS, // MANAGE_ONGOING_CALLS }; @@ -1784,9 +1785,9 @@ public class AppOpsManager { OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, OPSTR_NO_ISOLATED_STORAGE, - OPSTR_RESERVED_100, - OPSTR_RESERVED_101, - OPSTR_RESERVED_102, + OPSTR_PHONE_CALL_MICROPHONE, + OPSTR_PHONE_CALL_CAMERA, + OPSTR_RECORD_AUDIO_HOTWORD, OPSTR_MANAGE_ONGOING_CALLS, }; @@ -1895,9 +1896,9 @@ public class AppOpsManager { "AUTO_REVOKE_PERMISSIONS_IF_UNUSED", "AUTO_REVOKE_MANAGED_BY_INSTALLER", "NO_ISOLATED_STORAGE", - "RESERVED_100", - "RESERVED_101", - "RESERVED_102", + "PHONE_CALL_MICROPHONE", + "PHONE_CALL_CAMERA", + "RECORD_AUDIO_HOTWORD", "MANAGE_ONGOING_CALLS", }; @@ -2007,9 +2008,9 @@ public class AppOpsManager { null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER null, // no permission for OP_NO_ISOLATED_STORAGE - null, // OP_RESERVED_100 - null, // OP_RESERVED_101 - null, // OP_RESERVED_102 + null, // no permission for OP_PHONE_CALL_MICROPHONE + null, // no permission for OP_PHONE_CALL_CAMERA + null, // no permission for OP_RECORD_AUDIO_HOTWORD Manifest.permission.MANAGE_ONGOING_CALLS, }; @@ -2119,9 +2120,9 @@ public class AppOpsManager { null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // AUTO_REVOKE_MANAGED_BY_INSTALLER null, // NO_ISOLATED_STORAGE - null, // OP_RESERVED_100 - null, // OP_RESERVED_101 - null, // OP_RESERVED_102 + null, // PHONE_CALL_MICROPHONE + null, // PHONE_CALL_MICROPHONE + null, // RECORD_AUDIO_HOTWORD null, // MANAGE_ONGOING_CALLS }; @@ -2230,9 +2231,9 @@ public class AppOpsManager { null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // AUTO_REVOKE_MANAGED_BY_INSTALLER null, // NO_ISOLATED_STORAGE - null, // OP_RESERVED_100 - null, // OP_RESERVED_101 - null, // OP_RESERVED_102 + null, // PHONE_CALL_MICROPHONE + null, // PHONE_CALL_CAMERA + null, // RECORD_AUDIO_HOTWORD null, // MANAGE_ONGOING_CALLS }; @@ -2340,9 +2341,9 @@ public class AppOpsManager { AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER AppOpsManager.MODE_ERRORED, // OP_NO_ISOLATED_STORAGE - AppOpsManager.MODE_ERRORED, // OP_RESERVED_100 - AppOpsManager.MODE_ERRORED, // OP_RESERVED_101 - AppOpsManager.MODE_ERRORED, // OP_RESERVED_102 + AppOpsManager.MODE_ALLOWED, // PHONE_CALL_MICROPHONE + AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA + AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS }; @@ -2454,9 +2455,9 @@ public class AppOpsManager { false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED false, // AUTO_REVOKE_MANAGED_BY_INSTALLER true, // NO_ISOLATED_STORAGE - false, // OP_RESERVED_100 - false, // OP_RESERVED_101 - false, // OP_RESERVED_102 + false, // PHONE_CALL_MICROPHONE + false, // PHONE_CALL_CAMERA + false, // RECORD_AUDIO_HOTWORD true, // MANAGE_ONGOING_CALLS }; diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 4f065fd166bba38972483d9e505332385fb6349c..602b835a03f848415867df0caef461362ee2a948 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1901,10 +1901,8 @@ class ContextImpl extends Context { @Override public Object getSystemService(String name) { if (vmIncorrectContextUseEnabled()) { - // We may override this API from outer context. - final boolean isUiContext = isUiContext() || isOuterUiContext(); // Check incorrect Context usage. - if (isUiComponent(name) && !isUiContext) { + if (isUiComponent(name) && !isSelfOrOuterUiContext()) { final String errorMessage = "Tried to access visual service " + SystemServiceRegistry.getSystemServiceClassName(name) + " from a non-visual Context:" + getOuterContext(); @@ -1921,15 +1919,17 @@ class ContextImpl extends Context { return SystemServiceRegistry.getSystemService(this, name); } - private boolean isOuterUiContext() { - return getOuterContext() != null && getOuterContext().isUiContext(); - } - @Override public String getSystemServiceName(Class serviceClass) { return SystemServiceRegistry.getSystemServiceName(serviceClass); } + // TODO(b/149463653): check if we still need this method after migrating IMS to WindowContext. + private boolean isSelfOrOuterUiContext() { + // We may override outer context's isUiContext + return isUiContext() || getOuterContext() != null && getOuterContext().isUiContext(); + } + /** @hide */ @Override public boolean isUiContext() { @@ -2376,7 +2376,6 @@ class ContextImpl extends Context { context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId, overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(), mResources.getLoaders())); - context.mIsUiContext = isUiContext() || isOuterUiContext(); return context; } @@ -2396,6 +2395,11 @@ class ContextImpl extends Context { mResources.getLoaders())); context.mDisplay = display; context.mIsAssociatedWithDisplay = true; + // Note that even if a display context is derived from an UI context, it should not be + // treated as UI context because it does not handle configuration changes from the server + // side. If the context does need to handle configuration changes, please use + // Context#createWindowContext(int, Bundle). + context.mIsUiContext = false; return context; } @@ -2481,9 +2485,9 @@ class ContextImpl extends Context { @Override public Display getDisplay() { - if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay) { + if (!mIsSystemOrSystemUiContext && !mIsAssociatedWithDisplay && !isSelfOrOuterUiContext()) { throw new UnsupportedOperationException("Tried to obtain display from a Context not " - + "associated with one. Only visual Contexts (such as Activity or one created " + + "associated with one. Only visual Contexts (such as Activity or one created " + "with Context#createWindowContext) or ones created with " + "Context#createDisplayContext are associated with displays. Other types of " + "Contexts are typically related to background entities and may return an " @@ -2757,6 +2761,7 @@ class ContextImpl extends Context { mDisplay = container.mDisplay; mIsAssociatedWithDisplay = container.mIsAssociatedWithDisplay; mIsSystemOrSystemUiContext = container.mIsSystemOrSystemUiContext; + mIsUiContext = container.isSelfOrOuterUiContext(); } else { mBasePackageName = packageInfo.mPackageName; ApplicationInfo ainfo = packageInfo.getApplicationInfo(); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 75d8a19f8182fef9a089d085536cb47385ed86c9..2953a5af4b5c436c6411a395ba487ca6c7d80764 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -683,4 +683,14 @@ interface IActivityManager { * Kills uid with the reason of permission change. */ void killUidForPermissionChange(int appId, int userId, String reason); + + /** + * Control the app freezer state. Returns true in case of success, false if the operation + * didn't succeed (for example, when the app freezer isn't supported). + * Handling the freezer state via this method is reentrant, that is it can be + * disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to + * enable match, the freezer is re-enabled at last enable only. + * @param enable set it to true to enable the app freezer, false to disable it. + */ + boolean enableAppFreezer(in boolean enable); } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index a21a156e54599d415436946daf788857351671e4..7be661b957c0fab3d2802c2e64b1c360493bfcf8 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -801,12 +801,9 @@ public final class LoadedApk { makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths); - String libraryPermittedPath = mDataDir; - if (mActivityThread == null) { - // In a zygote context where mActivityThread is null we can't access the app data dir - // and including this in libraryPermittedPath would cause SELinux denials. - libraryPermittedPath = ""; - } + // Including an inaccessible dir in libraryPermittedPath would cause SELinux denials + // when the loader attempts to canonicalise the path. so we don't. + String libraryPermittedPath = canAccessDataDir() ? mDataDir : ""; if (isBundledApp) { // For bundled apps, add the base directory of the app (e.g., @@ -950,6 +947,33 @@ public final class LoadedApk { } } + /** + * Return whether we can access the package's private data directory in order to be able to + * load code from it. + */ + private boolean canAccessDataDir() { + // In a zygote context where mActivityThread is null we can't access the app data dir. + if (mActivityThread == null) { + return false; + } + + // A package can access its own data directory (the common case, so short-circuit it). + if (Objects.equals(mPackageName, ActivityThread.currentPackageName())) { + return true; + } + + // Temporarily disable logging of disk reads on the Looper thread as this is necessary - + // and the loader will access the directory anyway if we don't check it. + StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads(); + try { + // We are constructing a classloader for a different package. It is likely, + // but not certain, that we can't acccess its app data dir - so check. + return new File(mDataDir).canExecute(); + } finally { + setThreadPolicy(oldPolicy); + } + } + @UnsupportedAppUsage public ClassLoader getClassLoader() { synchronized (this) { diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 7aa51723e3cc4ee550681ae8d8e73b41b49fe25f..9c6e61c0c4ce51a22305c8642a3587b8dda222c9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -4801,7 +4801,6 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.time, View.GONE); contentView.setImageViewIcon(R.id.profile_badge, null); contentView.setViewVisibility(R.id.profile_badge, View.GONE); - contentView.setViewVisibility(R.id.alerted_icon, View.GONE); mN.mUsesStandardHeader = false; } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 747789901b9dbc841710508958cfe5fd77e81bc8..771528ad39c3b1b99b3b0c53aafcdf1444d04489 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -39,7 +39,6 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; -import android.util.LruCache; import android.util.Pair; import android.util.Slog; import android.view.Display; @@ -62,7 +61,6 @@ import java.util.List; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Consumer; -import java.util.function.Predicate; /** @hide */ public class ResourcesManager { @@ -129,17 +127,30 @@ public class ResourcesManager { } } - private static final boolean ENABLE_APK_ASSETS_CACHE = false; - /** - * The ApkAssets we are caching and intend to hold strong references to. + * Loads {@link ApkAssets} and caches them to prevent their garbage collection while the + * instance is alive and reachable. */ - private final LruCache mLoadedApkAssets = - (ENABLE_APK_ASSETS_CACHE) ? new LruCache<>(3) : null; + private class ApkAssetsSupplier { + final ArrayMap mLocalCache = new ArrayMap<>(); + + /** + * Retrieves the {@link ApkAssets} corresponding to the specified key, caches the ApkAssets + * within this instance, and inserts the loaded ApkAssets into the {@link #mCachedApkAssets} + * cache. + */ + ApkAssets load(final ApkKey apkKey) throws IOException { + ApkAssets apkAssets = mLocalCache.get(apkKey); + if (apkAssets == null) { + apkAssets = loadApkAssets(apkKey); + mLocalCache.put(apkKey, apkAssets); + } + return apkAssets; + } + } /** - * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't - * in our LRU cache. Bonus resources :) + * The ApkAssets that are being referenced in the wild that we can reuse. */ private final ArrayMap> mCachedApkAssets = new ArrayMap<>(); @@ -337,113 +348,116 @@ public class ResourcesManager { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } - private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay) - throws IOException { - final ApkKey newKey = new ApkKey(path, sharedLib, overlay); - ApkAssets apkAssets = null; - if (mLoadedApkAssets != null) { - apkAssets = mLoadedApkAssets.get(newKey); - if (apkAssets != null && apkAssets.isUpToDate()) { - return apkAssets; - } - } + private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { + ApkAssets apkAssets; // Optimistically check if this ApkAssets exists somewhere else. - final WeakReference apkAssetsRef = mCachedApkAssets.get(newKey); - if (apkAssetsRef != null) { - apkAssets = apkAssetsRef.get(); - if (apkAssets != null && apkAssets.isUpToDate()) { - if (mLoadedApkAssets != null) { - mLoadedApkAssets.put(newKey, apkAssets); + synchronized (this) { + final WeakReference apkAssetsRef = mCachedApkAssets.get(key); + if (apkAssetsRef != null) { + apkAssets = apkAssetsRef.get(); + if (apkAssets != null && apkAssets.isUpToDate()) { + return apkAssets; + } else { + // Clean up the reference. + mCachedApkAssets.remove(key); } - - return apkAssets; - } else { - // Clean up the reference. - mCachedApkAssets.remove(newKey); } } // We must load this from disk. - if (overlay) { - apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), 0 /*flags*/); + if (key.overlay) { + apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), + 0 /*flags*/); } else { - apkAssets = ApkAssets.loadFromPath(path, sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); + apkAssets = ApkAssets.loadFromPath(key.path, + key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); } - if (mLoadedApkAssets != null) { - mLoadedApkAssets.put(newKey, apkAssets); + synchronized (this) { + mCachedApkAssets.put(key, new WeakReference<>(apkAssets)); } - mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets)); return apkAssets; } /** - * Creates an AssetManager from the paths within the ResourcesKey. - * - * This can be overridden in tests so as to avoid creating a real AssetManager with - * real APK paths. - * @param key The key containing the resource paths to add to the AssetManager. - * @return a new AssetManager. - */ - @VisibleForTesting - @UnsupportedAppUsage - protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { - final AssetManager.Builder builder = new AssetManager.Builder(); + * Retrieves a list of apk keys representing the ApkAssets that should be loaded for + * AssetManagers mapped to the {@param key}. + */ + private static @NonNull ArrayList extractApkKeys(@NonNull final ResourcesKey key) { + final ArrayList apkKeys = new ArrayList<>(); // resDir can be null if the 'android' package is creating a new Resources object. // This is fine, since each AssetManager automatically loads the 'android' package // already. if (key.mResDir != null) { - try { - builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.e(TAG, "failed to add asset path " + key.mResDir); - return null; - } + apkKeys.add(new ApkKey(key.mResDir, false /*sharedLib*/, false /*overlay*/)); } if (key.mSplitResDirs != null) { for (final String splitResDir : key.mSplitResDirs) { - try { - builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.e(TAG, "failed to add split asset path " + splitResDir); - return null; - } + apkKeys.add(new ApkKey(splitResDir, false /*sharedLib*/, false /*overlay*/)); } } if (key.mLibDirs != null) { for (final String libDir : key.mLibDirs) { + // Avoid opening files we know do not have resources, like code-only .jar files. if (libDir.endsWith(".apk")) { - // Avoid opening files we know do not have resources, - // like code-only .jar files. - try { - builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.w(TAG, "Asset path '" + libDir + - "' does not exist or contains no resources."); - - // continue. - } + apkKeys.add(new ApkKey(libDir, true /*sharedLib*/, false /*overlay*/)); } } } if (key.mOverlayDirs != null) { for (final String idmapPath : key.mOverlayDirs) { - try { - builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/, - true /*overlay*/)); - } catch (IOException e) { - Log.w(TAG, "failed to add overlay path " + idmapPath); + apkKeys.add(new ApkKey(idmapPath, false /*sharedLib*/, true /*overlay*/)); + } + } - // continue. + return apkKeys; + } + + /** + * Creates an AssetManager from the paths within the ResourcesKey. + * + * This can be overridden in tests so as to avoid creating a real AssetManager with + * real APK paths. + * @param key The key containing the resource paths to add to the AssetManager. + * @return a new AssetManager. + */ + @VisibleForTesting + @UnsupportedAppUsage + protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { + return createAssetManager(key, /* apkSupplier */ null); + } + + /** + * Variant of {@link #createAssetManager(ResourcesKey)} that attempts to load ApkAssets + * from an {@link ApkAssetsSupplier} if non-null; otherwise ApkAssets are loaded using + * {@link #loadApkAssets(ApkKey)}. + */ + private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key, + @Nullable ApkAssetsSupplier apkSupplier) { + final AssetManager.Builder builder = new AssetManager.Builder(); + + final ArrayList apkKeys = extractApkKeys(key); + for (int i = 0, n = apkKeys.size(); i < n; i++) { + final ApkKey apkKey = apkKeys.get(i); + try { + builder.addApkAssets( + (apkSupplier != null) ? apkSupplier.load(apkKey) : loadApkAssets(apkKey)); + } catch (IOException e) { + if (apkKey.overlay) { + Log.w(TAG, String.format("failed to add overlay path '%s'", apkKey.path), e); + } else if (apkKey.sharedLib) { + Log.w(TAG, String.format( + "asset path '%s' does not exist or contains no resources", + apkKey.path), e); + } else { + Log.e(TAG, String.format("failed to add asset path '%s'", apkKey.path), e); + return null; } } } @@ -480,24 +494,6 @@ public class ResourcesManager { pw.println("ResourcesManager:"); pw.increaseIndent(); - if (mLoadedApkAssets != null) { - pw.print("cached apks: total="); - pw.print(mLoadedApkAssets.size()); - pw.print(" created="); - pw.print(mLoadedApkAssets.createCount()); - pw.print(" evicted="); - pw.print(mLoadedApkAssets.evictionCount()); - pw.print(" hit="); - pw.print(mLoadedApkAssets.hitCount()); - pw.print(" miss="); - pw.print(mLoadedApkAssets.missCount()); - pw.print(" max="); - pw.print(mLoadedApkAssets.maxSize()); - } else { - pw.print("cached apks: 0 [cache disabled]"); - } - pw.println(); - pw.print("total apks: "); pw.println(countLiveReferences(mCachedApkAssets.values())); @@ -533,11 +529,12 @@ public class ResourcesManager { return config; } - private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) { + private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key, + @Nullable ApkAssetsSupplier apkSupplier) { final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration); daj.setCompatibilityInfo(key.mCompatInfo); - final AssetManager assets = createAssetManager(key); + final AssetManager assets = createAssetManager(key, apkSupplier); if (assets == null) { return null; } @@ -575,9 +572,18 @@ public class ResourcesManager { */ private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( @NonNull ResourcesKey key) { + return findOrCreateResourcesImplForKeyLocked(key, /* apkSupplier */ null); + } + + /** + * Variant of {@link #findOrCreateResourcesImplForKeyLocked(ResourcesKey)} that attempts to + * load ApkAssets from a {@link ApkAssetsSupplier} when creating a new ResourcesImpl. + */ + private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( + @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) { ResourcesImpl impl = findResourcesImplForKeyLocked(key); if (impl == null) { - impl = createResourcesImpl(key); + impl = createResourcesImpl(key, apkSupplier); if (impl != null) { mResourceImpls.put(key, new WeakReference<>(impl)); } @@ -766,7 +772,7 @@ public class ResourcesManager { } // Now request an actual Resources object. - return createResources(token, key, classLoader); + return createResources(token, key, classLoader, /* apkSupplier */ null); } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } @@ -809,6 +815,31 @@ public class ResourcesManager { (ref) -> ref == null || deadReferences.contains(ref)); } + /** + * Creates an {@link ApkAssetsSupplier} and loads all the ApkAssets required by the {@param key} + * into the supplier. This should be done while the lock is not held to prevent performing I/O + * while holding the lock. + */ + private @NonNull ApkAssetsSupplier createApkAssetsSupplierNotLocked(@NonNull ResourcesKey key) { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#createApkAssetsSupplierNotLocked"); + try { + final ApkAssetsSupplier supplier = new ApkAssetsSupplier(); + final ArrayList apkKeys = extractApkKeys(key); + for (int i = 0, n = apkKeys.size(); i < n; i++) { + final ApkKey apkKey = apkKeys.get(i); + try { + supplier.load(apkKey); + } catch (IOException e) { + Log.w(TAG, String.format("failed to preload asset path '%s'", apkKey.path), e); + } + } + return supplier; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } + } + /** * Creates a Resources object set with a ResourcesImpl object matching the given key. * @@ -816,12 +847,14 @@ public class ResourcesManager { * @param key The key describing the parameters of the ResourcesImpl object. * @param classLoader The classloader to use for the Resources object. * If null, {@link ClassLoader#getSystemClassLoader()} is used. + * @param apkSupplier The apk assets supplier to use when creating a new ResourcesImpl object. * @return A Resources object that gets updated when * {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)} * is called. */ private @Nullable Resources createResources(@Nullable IBinder activityToken, - @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) { + @NonNull ResourcesKey key, @NonNull ClassLoader classLoader, + @Nullable ApkAssetsSupplier apkSupplier) { synchronized (this) { if (DEBUG) { Throwable here = new Throwable(); @@ -829,7 +862,7 @@ public class ResourcesManager { Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here); } - ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key); + ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier); if (resourcesImpl == null) { return null; } @@ -898,7 +931,10 @@ public class ResourcesManager { rebaseKeyForActivity(activityToken, key); } - return createResources(activityToken, key, classLoader); + // Preload the ApkAssets required by the key to prevent performing heavy I/O while the + // ResourcesManager lock is held. + final ApkAssetsSupplier assetsSupplier = createApkAssetsSupplierNotLocked(key); + return createResources(activityToken, key, classLoader, assetsSupplier); } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } @@ -969,7 +1005,13 @@ public class ResourcesManager { final ResourcesKey newKey = rebaseActivityOverrideConfig(resources, oldConfig, overrideConfig, displayId); if (newKey != null) { - updateActivityResources(resources, newKey, false); + final ResourcesImpl resourcesImpl = + findOrCreateResourcesImplForKeyLocked(newKey); + if (resourcesImpl != null && resourcesImpl != resources.getImpl()) { + // Set the ResourcesImpl, updating it for all users of this Resources + // object. + resources.setImpl(resourcesImpl); + } } } } @@ -1024,33 +1066,21 @@ public class ResourcesManager { return newKey; } - private void updateActivityResources(Resources resources, ResourcesKey newKey, - boolean hasLoader) { - final ResourcesImpl resourcesImpl; - - if (hasLoader) { - // Loaders always get new Impls because they cannot be shared - resourcesImpl = createResourcesImpl(newKey); - } else { - resourcesImpl = findOrCreateResourcesImplForKeyLocked(newKey); - } - - if (resourcesImpl != null && resourcesImpl != resources.getImpl()) { - // Set the ResourcesImpl, updating it for all users of this Resources - // object. - resources.setImpl(resourcesImpl); - } - } - public final boolean applyConfigurationToResources(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { synchronized(this) { - return applyConfigurationToResourcesLocked(config, compat); + return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */); } } public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, - @Nullable CompatibilityInfo compat) { + @Nullable CompatibilityInfo compat) { + return applyConfigurationToResourcesLocked(config, compat, null /* adjustments */); + } + + /** Applies the global configuration to the managed resources. */ + public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, + @Nullable CompatibilityInfo compat, @Nullable DisplayAdjustments adjustments) { try { Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#applyConfigurationToResourcesLocked"); @@ -1074,6 +1104,11 @@ public class ResourcesManager { | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; } + if (adjustments != null) { + // Currently the only case where the adjustment takes effect is to simulate placing + // an app in a rotated display. + adjustments.adjustGlobalAppMetrics(defaultDisplayMetrics); + } Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat); ApplicationPackageManager.configurationChanged(); diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 5fcf495932681301775c09deda5db280d50aabc6..c2aa643c3ee4c8c3a5f3a0150b68d95faafcaaf8 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -177,6 +177,13 @@ public class TaskInfo { */ public boolean isResizeable; + /** + * Screen orientation set by {@link #baseActivity} via + * {@link Activity#setRequestedOrientation(int)}. + * @hide + */ + public @ActivityInfo.ScreenOrientation int requestedOrientation; + TaskInfo() { // Do nothing } @@ -248,6 +255,7 @@ public class TaskInfo { ? ActivityInfo.CREATOR.createFromParcel(source) : null; isResizeable = source.readBoolean(); + requestedOrientation = source.readInt(); } /** @@ -298,6 +306,7 @@ public class TaskInfo { topActivityInfo.writeToParcel(dest, flags); } dest.writeBoolean(isResizeable); + dest.writeInt(requestedOrientation); } @Override @@ -316,6 +325,7 @@ public class TaskInfo { + " token=" + token + " topActivityType=" + topActivityType + " pictureInPictureParams=" + pictureInPictureParams - + " topActivityInfo=" + topActivityInfo; + + " topActivityInfo=" + topActivityInfo + + " requestedOrientation=" + requestedOrientation; } } diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 558e222566489421f519810660b1448f377ae97d..e2fc5dbf10e238c2fe1e953eb9d1fb0ed5f9076b 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -509,6 +509,9 @@ public class UiModeManager { } /** + * Activating night mode for the current user + * + * @return {@code true} if the change is successful * @hide */ public boolean setNightModeActivated(boolean active) { diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java index 4517c6deb5b4c320403d31224c57a4c55194ceb3..fd1b9e3bede2ecc5c627767d196806fedaf633c4 100644 --- a/core/java/android/app/prediction/AppPredictor.java +++ b/core/java/android/app/prediction/AppPredictor.java @@ -82,6 +82,8 @@ public final class AppPredictor { private final AppPredictionSessionId mSessionId; private final ArrayMap mRegisteredCallbacks = new ArrayMap<>(); + private final IBinder mToken = new Binder(); + /** * Creates a new Prediction client. *

@@ -97,7 +99,7 @@ public final class AppPredictor { mSessionId = new AppPredictionSessionId( context.getPackageName() + ":" + UUID.randomUUID().toString(), context.getUserId()); try { - mPredictionManager.createPredictionSession(predictionContext, mSessionId); + mPredictionManager.createPredictionSession(predictionContext, mSessionId, mToken); } catch (RemoteException e) { Log.e(TAG, "Failed to create predictor", e); e.rethrowAsRuntimeException(); diff --git a/core/java/android/app/prediction/IPredictionManager.aidl b/core/java/android/app/prediction/IPredictionManager.aidl index 587e3fd523776f438f1d0156b70724bb50e6864c..863fc6f952ddf997de7b64e001d9f2fc23d9cd1b 100644 --- a/core/java/android/app/prediction/IPredictionManager.aidl +++ b/core/java/android/app/prediction/IPredictionManager.aidl @@ -29,7 +29,7 @@ import android.content.pm.ParceledListSlice; interface IPredictionManager { void createPredictionSession(in AppPredictionContext context, - in AppPredictionSessionId sessionId); + in AppPredictionSessionId sessionId, in IBinder token); void notifyAppTargetEvent(in AppPredictionSessionId sessionId, in AppTargetEvent event); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index db579128b2387bde934f6a7e5add8917ef1cd0d6..005c7ce9d9496dbff75a3ceaa26c36960a18ed9a 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1292,9 +1292,8 @@ public class PackageInstaller { * * @throws PackageManager.NameNotFoundException if the new owner could not be found. * @throws SecurityException if called after the session has been committed or abandoned. - * @throws SecurityException if the session does not update the original installer - * @throws SecurityException if streams opened through - * {@link #openWrite(String, long, long) are still open. + * @throws IllegalArgumentException if streams opened through + * {@link #openWrite(String, long, long) are still open. */ public void transfer(@NonNull String packageName) throws PackageManager.NameNotFoundException { diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index aca5b458a2d61465b34280351262f2ca02462d03..08b23b04f2aeb1e9cdcfeeafb5fa8258e54fff03 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -220,6 +220,14 @@ public class UserInfo implements Parcelable { */ public boolean preCreated; + /** + * When {@code true}, it indicates this user was created by converting a {@link #preCreated} + * user. + * + *

NOTE: only used for debugging purposes, it's not set when marshalled to a parcel. + */ + public boolean convertedFromPreCreated; + /** * Creates a UserInfo whose user type is determined automatically by the flags according to * {@link #getDefaultUserType}; can only be used for user types handled there. @@ -413,6 +421,7 @@ public class UserInfo implements Parcelable { lastLoggedInFingerprint = orig.lastLoggedInFingerprint; partial = orig.partial; preCreated = orig.preCreated; + convertedFromPreCreated = orig.convertedFromPreCreated; profileGroupId = orig.profileGroupId; restrictedProfileParentId = orig.restrictedProfileParentId; guestToRemove = orig.guestToRemove; @@ -440,6 +449,7 @@ public class UserInfo implements Parcelable { + ", type=" + userType + ", flags=" + flagsToString(flags) + (preCreated ? " (pre-created)" : "") + + (convertedFromPreCreated ? " (converted)" : "") + (partial ? " (partial)" : "") + "]"; } diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index ccb8c446acb19eabd5a402ff82b407cd5e9201b7..3d6ac72724b723cc388a0e8161bae5fe23e53677 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -45,7 +45,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; -import android.app.UiModeManager; import android.app.WindowConfiguration; import android.compat.annotation.UnsupportedAppUsage; import android.content.LocaleProto; @@ -928,7 +927,13 @@ public final class Configuration implements Parcelable, Comparable> /** *

The desired zoom ratio

- *

Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the - * application can now choose to use this tag to specify the desired zoom level. The - * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical - * crop to achieve aspect ratios different than the native camera sensor.

+ *

Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to + * use this tag to specify the desired zoom level.

*

By using this control, the application gains a simpler way to control zoom, which can * be a combination of optical and digital zoom. For example, a multi-camera system may * contain more than one lens with different focal lengths, and the user can use optical @@ -2861,11 +2859,18 @@ public final class CaptureRequest extends CameraMetadata> * respectively.

*

The camera device may adjust the crop region to account for rounding and other hardware * requirements; the final crop region used will be included in the output capture result.

+ *

The camera sensor output aspect ratio depends on factors such as output stream + * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using + * this control. And the camera device will treat different camera sensor output sizes + * (potentially with in-sensor crop) as the same crop of + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the + * maximum crop region always maps to the same aspect ratio or field of view for the + * sensor output.

*

Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} * to take advantage of better support for zoom with logical multi-camera. The benefits * include better precision with optical-digital zoom combination, and ability to do * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in - * the capture request must be either letterboxing or pillarboxing (but not both). The + * the capture request should be left as the default activeArray size. The * coordinate system is post-zoom, meaning that the activeArraySize or * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.

@@ -2875,6 +2880,7 @@ public final class CaptureRequest extends CameraMetadata> * capability and mode

*

This key is available on all devices.

* + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE * @see CaptureRequest#CONTROL_ZOOM_RATIO * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index cc4d278948f3cfb39ea5ff797e753b95909632da..41f4df7dbc99aaf8271c936e0a6e7a2156defd12 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -2406,10 +2406,8 @@ public class CaptureResult extends CameraMetadata> { /** *

The desired zoom ratio

- *

Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} with dual purposes of crop and zoom, the - * application can now choose to use this tag to specify the desired zoom level. The - * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} can still be used to specify the horizontal or vertical - * crop to achieve aspect ratios different than the native camera sensor.

+ *

Instead of using {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} for zoom, the application can now choose to + * use this tag to specify the desired zoom level.

*

By using this control, the application gains a simpler way to control zoom, which can * be a combination of optical and digital zoom. For example, a multi-camera system may * contain more than one lens with different focal lengths, and the user can use optical @@ -3507,11 +3505,18 @@ public class CaptureResult extends CameraMetadata> { * respectively.

*

The camera device may adjust the crop region to account for rounding and other hardware * requirements; the final crop region used will be included in the output capture result.

+ *

The camera sensor output aspect ratio depends on factors such as output stream + * combination and {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE android.control.aeTargetFpsRange}, and shouldn't be adjusted by using + * this control. And the camera device will treat different camera sensor output sizes + * (potentially with in-sensor crop) as the same crop of + * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}. As a result, the application shouldn't assume the + * maximum crop region always maps to the same aspect ratio or field of view for the + * sensor output.

*

Starting from API level 30, it's strongly recommended to use {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} * to take advantage of better support for zoom with logical multi-camera. The benefits * include better precision with optical-digital zoom combination, and ability to do * zoom-out from 1.0x. When using {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for zoom, the crop region in - * the capture request must be either letterboxing or pillarboxing (but not both). The + * the capture request should be left as the default activeArray size. The * coordinate system is post-zoom, meaning that the activeArraySize or * preCorrectionActiveArraySize covers the camera device's field of view "after" zoom. See * {@link CaptureRequest#CONTROL_ZOOM_RATIO android.control.zoomRatio} for details.

@@ -3521,6 +3526,7 @@ public class CaptureResult extends CameraMetadata> { * capability and mode

*

This key is available on all devices.

* + * @see CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE * @see CaptureRequest#CONTROL_ZOOM_RATIO * @see CaptureRequest#DISTORTION_CORRECTION_MODE * @see CameraCharacteristics#SCALER_AVAILABLE_MAX_DIGITAL_ZOOM diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 1ea6f2849b3a84841989a4a50ae3df545155f5d6..fad80cb8ec322f07f86bff3618819fd134baec3c 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -19,6 +19,7 @@ package android.hardware.fingerprint; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.MANAGE_FINGERPRINT; import static android.Manifest.permission.USE_BIOMETRIC; +import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.Manifest.permission.USE_FINGERPRINT; import android.annotation.NonNull; @@ -76,11 +77,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing private static final int MSG_ERROR = 104; private static final int MSG_REMOVED = 105; private static final int MSG_ENUMERATED = 106; + private static final int MSG_FINGERPRINT_DETECTED = 107; private IFingerprintService mService; private Context mContext; private IBinder mToken = new Binder(); private AuthenticationCallback mAuthenticationCallback; + private FingerprintDetectionCallback mFingerprintDetectionCallback; private EnrollmentCallback mEnrollmentCallback; private RemovalCallback mRemovalCallback; private EnumerateCallback mEnumerateCallback; @@ -108,6 +111,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } + private class OnFingerprintDetectionCancelListener implements OnCancelListener { + @Override + public void onCancel() { + cancelFingerprintDetect(); + } + } + /** * A wrapper class for the crypto objects supported by FingerprintManager. Currently the * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. @@ -272,6 +282,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing public void onAuthenticationAcquired(int acquireInfo) {} }; + /** + * Callback structure provided for {@link #detectFingerprint(CancellationSignal, + * FingerprintDetectionCallback, int)}. + * @hide + */ + public interface FingerprintDetectionCallback { + /** + * Invoked when a fingerprint has been detected. + */ + void onFingerprintDetected(int userId, boolean isStrongBiometric); + } + /** * Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal, * int, int, EnrollmentCallback)} must provide an implementation of this for listening to @@ -454,6 +476,35 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } + /** + * Uses the fingerprint hardware to detect for the presence of a finger, without giving details + * about accept/reject/lockout. + * @hide + */ + @RequiresPermission(USE_BIOMETRIC_INTERNAL) + public void detectFingerprint(@NonNull CancellationSignal cancel, + @NonNull FingerprintDetectionCallback callback, int userId) { + if (mService == null) { + return; + } + + if (cancel.isCanceled()) { + Slog.w(TAG, "Detection already cancelled"); + return; + } else { + cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener()); + } + + mFingerprintDetectionCallback = callback; + + try { + mService.detectFingerprint(mToken, userId, mServiceReceiver, + mContext.getOpPackageName()); + } catch (RemoteException e) { + Slog.w(TAG, "Remote exception when requesting finger detect", e); + } + } + /** * Request fingerprint enrollment. This call warms up the fingerprint hardware * and starts scanning for fingerprints. Progress will be indicated by callbacks to the @@ -798,6 +849,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */, msg.arg2 /* groupId */); break; + case MSG_FINGERPRINT_DETECTED: + sendFingerprintDetected(msg.arg1 /* userId */, + (boolean) msg.obj /* isStrongBiometric */); + break; } } }; @@ -892,6 +947,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } + private void sendFingerprintDetected(int userId, boolean isStrongBiometric) { + if (mFingerprintDetectionCallback == null) { + Slog.e(TAG, "sendFingerprintDetected, callback null"); + return; + } + mFingerprintDetectionCallback.onFingerprintDetected(userId, isStrongBiometric); + } + /** * @hide */ @@ -928,6 +991,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } } + private void cancelFingerprintDetect() { + if (mService == null) { + return; + } + + try { + mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * @hide */ @@ -1033,6 +1108,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing fp).sendToTarget(); } + @Override + public void onFingerprintDetected(long deviceId, int userId, boolean isStrongBiometric) { + mHandler.obtainMessage(MSG_FINGERPRINT_DETECTED, userId, 0, isStrongBiometric) + .sendToTarget(); + } + @Override // binder call public void onAuthenticationFailed(long deviceId) { mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget(); diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl index c5c375543adc90b5e6a413674de098ac37c3eefa..8aa36d7d5d766af1e7a8e10a2cce0007d8d959e8 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl @@ -33,6 +33,11 @@ interface IFingerprintService { void authenticate(IBinder token, long sessionId, int userId, IFingerprintServiceReceiver receiver, int flags, String opPackageName); + // Uses the fingerprint hardware to detect for the presence of a finger, without giving details + // about accept/reject/lockout. + void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver, + String opPackageName); + // This method prepares the service to start authenticating, but doesn't start authentication. // This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be // called from BiometricService. The additional uid, pid, userId arguments should be determined @@ -48,6 +53,9 @@ interface IFingerprintService { // Cancel authentication for the given sessionId void cancelAuthentication(IBinder token, String opPackageName); + // Cancel finger detection + void cancelFingerprintDetect(IBinder token, String opPackageName); + // Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes // an additional uid, pid, userid. void cancelAuthenticationFromService(IBinder token, String opPackageName, diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl index 4412cee31bb0712a9a3c655c96e6caa85cda798d..a84b81e1eb81252f6664e266526251aafe177e8d 100644 --- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl +++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl @@ -26,6 +26,7 @@ oneway interface IFingerprintServiceReceiver { void onAcquired(long deviceId, int acquiredInfo, int vendorCode); void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId, boolean isStrongBiometric); + void onFingerprintDetected(long deviceId, int userId, boolean isStrongBiometric); void onAuthenticationFailed(long deviceId); void onError(long deviceId, int error, int vendorCode); void onRemoved(long deviceId, int fingerId, int groupId, int remaining); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 6c6bd004e3435d34f170901a2b93138b0274498e..0924e9f5eb7c24ebb0a89bb5726024889fd60413 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -1208,15 +1208,19 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true); // IME layout should always be inset by navigation bar, no matter its current visibility, - // unless automotive requests it, since automotive may hide the navigation bar. + // unless automotive requests it. Automotive devices may request the navigation bar to be + // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard) + // in order to maximize the visible screen real estate. When this happens, the IME window + // should animate from the bottom of the screen to reduce the jank that happens from the + // lack of synchronization between the bottom system window and the IME window. + if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) { + mWindow.getWindow().setDecorFitsSystemWindows(false); + } mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( (v, insets) -> v.onApplyWindowInsets( new WindowInsets.Builder(insets).setInsets( navigationBars(), - mIsAutomotive && mAutomotiveHideNavBarForKeyboard - ? android.graphics.Insets.NONE - : insets.getInsetsIgnoringVisibility(navigationBars()) - ) + insets.getInsetsIgnoringVisibility(navigationBars())) .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 683993f762c05f471b69a830cec9bd83c838fa65..0185ba444ca4dcd2fa1329a4b9814989f8b5e4eb 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.util.Log; import android.util.SparseIntArray; @@ -255,7 +256,12 @@ public final class BinderProxy implements IBinder { // out of system_server to all processes hosting binder objects it holds a reference to; // since some of those processes might be frozen, we don't want to block here // forever. Disable the freezer. - Process.enableFreezer(false); + try { + ActivityManager.getService().enableAppFreezer(false); + } catch (RemoteException e) { + Log.e(Binder.TAG, "RemoteException while disabling app freezer"); + } + for (WeakReference weakRef : proxiesToQuery) { BinderProxy bp = weakRef.get(); String key; @@ -278,7 +284,11 @@ public final class BinderProxy implements IBinder { counts.put(key, i + 1); } } - Process.enableFreezer(true); + try { + ActivityManager.getService().enableAppFreezer(true); + } catch (RemoteException e) { + Log.e(Binder.TAG, "RemoteException while re-enabling app freezer"); + } Map.Entry[] sorted = counts.entrySet().toArray( new Map.Entry[counts.size()]); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 3e77022d6bc1e6712c1a771839582ffe4fc0622e..78ba7f0eec28b96f4306e103db36eb9b0a11b2be 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -1012,15 +1012,33 @@ public class Build { /** * Q. - *

- * Why? Why, to give you a taste of your future, a preview of things - * to come. Con permiso, Capitan. The hall is rented, the orchestra - * engaged. It's now time to see if you can dance. + * + *

Applications targeting this or a later release will get these new changes in behavior. + * For more information about this release, see the + * Android 10 overview.

+ * + * */ public static final int Q = 29; /** * R. + * + *

Applications targeting this or a later release will get these new changes in behavior. + * For more information about this release, see the + * Android 11 overview.

+ * + * */ public static final int R = 30; diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index a6b869d1986753c3003208b34d2dfa4fc9ae3d61..df1f1b21eba32290564281e85895d09581098fcb 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -64,10 +64,11 @@ public class GraphicsEnvironment { private static final String SYSTEM_DRIVER_NAME = "system"; private static final String SYSTEM_DRIVER_VERSION_NAME = ""; private static final long SYSTEM_DRIVER_VERSION_CODE = 0; - private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; + private static final String PROPERTY_GFX_DRIVER_PRODUCTION = "ro.gfx.driver.0"; private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1"; private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time"; - private static final String METADATA_DRIVER_BUILD_TIME = "com.android.gamedriver.build_time"; + private static final String METADATA_DRIVER_BUILD_TIME = + "com.android.graphics.driver.build_time"; private static final String METADATA_DEVELOPER_DRIVER_ENABLE = "com.android.graphics.developerdriver.enable"; private static final String METADATA_INJECT_LAYERS_ENABLE = @@ -78,20 +79,20 @@ public class GraphicsEnvironment { private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE = "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE"; private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message"; - private static final String GAME_DRIVER_ALLOWLIST_ALL = "*"; - private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; + private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*"; + private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt"; private static final int VULKAN_1_0 = 0x00400000; private static final int VULKAN_1_1 = 0x00401000; - // GAME_DRIVER_ALL_APPS + // UPDATABLE_DRIVER_ALL_APPS // 0: Default (Invalid values fallback to default as well) - // 1: All apps use Game Driver - // 2: All apps use Prerelease Driver + // 1: All apps use updatable production driver + // 2: All apps use updatable prerelease driver // 3: All apps use system graphics driver - private static final int GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT = 0; - private static final int GAME_DRIVER_GLOBAL_OPT_IN_GAME_DRIVER = 1; - private static final int GAME_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2; - private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3; + private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_DEFAULT = 0; + private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRODUCTION_DRIVER = 1; + private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2; + private static final int UPDATABLE_DRIVER_GLOBAL_OPT_IN_OFF = 3; private ClassLoader mClassLoader; private String mLibrarySearchPaths; @@ -722,14 +723,17 @@ public class GraphicsEnvironment { * Return the driver package name to use. Return null for system driver. */ private static String chooseDriverInternal(Bundle coreSettings, ApplicationInfo ai) { - final String gameDriver = SystemProperties.get(PROPERTY_GFX_DRIVER); - final boolean hasGameDriver = gameDriver != null && !gameDriver.isEmpty(); + final String productionDriver = SystemProperties.get(PROPERTY_GFX_DRIVER_PRODUCTION); + final boolean hasProductionDriver = productionDriver != null && !productionDriver.isEmpty(); final String prereleaseDriver = SystemProperties.get(PROPERTY_GFX_DRIVER_PRERELEASE); final boolean hasPrereleaseDriver = prereleaseDriver != null && !prereleaseDriver.isEmpty(); - if (!hasGameDriver && !hasPrereleaseDriver) { - if (DEBUG) Log.v(TAG, "Neither Game Driver nor prerelease driver is supported."); + if (!hasProductionDriver && !hasPrereleaseDriver) { + if (DEBUG) { + Log.v(TAG, + "Neither updatable production driver nor prerelease driver is supported."); + } return null; } @@ -745,56 +749,59 @@ public class GraphicsEnvironment { (ai.metaData != null && ai.metaData.getBoolean(METADATA_DEVELOPER_DRIVER_ENABLE)) || isDebuggable(); - // Priority for Game Driver settings global on confliction (Higher priority comes first): - // 1. GAME_DRIVER_ALL_APPS - // 2. GAME_DRIVER_OPT_OUT_APPS - // 3. GAME_DRIVER_PRERELEASE_OPT_IN_APPS - // 4. GAME_DRIVER_OPT_IN_APPS - // 5. GAME_DRIVER_DENYLIST - // 6. GAME_DRIVER_ALLOWLIST - switch (coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0)) { - case GAME_DRIVER_GLOBAL_OPT_IN_OFF: - if (DEBUG) Log.v(TAG, "Game Driver is turned off on this device."); + // Priority of updatable driver settings on confliction (Higher priority comes first): + // 1. UPDATABLE_DRIVER_ALL_APPS + // 2. UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS + // 3. UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS + // 4. UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS + // 5. UPDATABLE_DRIVER_PRODUCTION_DENYLIST + // 6. UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST + switch (coreSettings.getInt(Settings.Global.UPDATABLE_DRIVER_ALL_APPS, 0)) { + case UPDATABLE_DRIVER_GLOBAL_OPT_IN_OFF: + if (DEBUG) Log.v(TAG, "updatable driver is turned off on this device."); return null; - case GAME_DRIVER_GLOBAL_OPT_IN_GAME_DRIVER: - if (DEBUG) Log.v(TAG, "All apps opt in to use Game Driver."); - return hasGameDriver ? gameDriver : null; - case GAME_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER: - if (DEBUG) Log.v(TAG, "All apps opt in to use prerelease driver."); + case UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRODUCTION_DRIVER: + if (DEBUG) Log.v(TAG, "All apps opt in to use updatable production driver."); + return hasProductionDriver ? productionDriver : null; + case UPDATABLE_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER: + if (DEBUG) Log.v(TAG, "All apps opt in to use updatable prerelease driver."); return hasPrereleaseDriver && enablePrereleaseDriver ? prereleaseDriver : null; - case GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT: + case UPDATABLE_DRIVER_GLOBAL_OPT_IN_DEFAULT: default: break; } final String appPackageName = ai.packageName; - if (getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS) + if (getGlobalSettingsString(null, coreSettings, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS) .contains(appPackageName)) { - if (DEBUG) Log.v(TAG, "App opts out for Game Driver."); + if (DEBUG) Log.v(TAG, "App opts out for updatable production driver."); return null; } if (getGlobalSettingsString( - null, coreSettings, Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS) + null, coreSettings, Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS) .contains(appPackageName)) { - if (DEBUG) Log.v(TAG, "App opts in for prerelease Game Driver."); + if (DEBUG) Log.v(TAG, "App opts in for updatable prerelease driver."); return hasPrereleaseDriver && enablePrereleaseDriver ? prereleaseDriver : null; } - // Early return here since the rest logic is only for Game Driver. - if (!hasGameDriver) { - if (DEBUG) Log.v(TAG, "Game Driver is not supported on the device."); + // Early return here since the rest logic is only for updatable production Driver. + if (!hasProductionDriver) { + if (DEBUG) Log.v(TAG, "Updatable production driver is not supported on the device."); return null; } final boolean isOptIn = - getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS) + getGlobalSettingsString(null, coreSettings, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS) .contains(appPackageName); final List allowlist = - getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_ALLOWLIST); - if (!isOptIn && allowlist.indexOf(GAME_DRIVER_ALLOWLIST_ALL) != 0 + getGlobalSettingsString(null, coreSettings, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST); + if (!isOptIn && allowlist.indexOf(UPDATABLE_DRIVER_ALLOWLIST_ALL) != 0 && !allowlist.contains(appPackageName)) { - if (DEBUG) Log.v(TAG, "App is not on the allowlist for Game Driver."); + if (DEBUG) Log.v(TAG, "App is not on the allowlist for updatable production driver."); return null; } @@ -802,13 +809,13 @@ public class GraphicsEnvironment { // terminate early if it's on the denylist and fallback to system driver. if (!isOptIn && getGlobalSettingsString( - null, coreSettings, Settings.Global.GAME_DRIVER_DENYLIST) + null, coreSettings, Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST) .contains(appPackageName)) { - if (DEBUG) Log.v(TAG, "App is on the denylist for Game Driver."); + if (DEBUG) Log.v(TAG, "App is on the denylist for updatable production driver."); return null; } - return gameDriver; + return productionDriver; } /** @@ -871,9 +878,10 @@ public class GraphicsEnvironment { throw new NullPointerException("apk's meta-data cannot be null"); } - final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME); - if (driverBuildTime == null || driverBuildTime.isEmpty()) { - throw new IllegalArgumentException("com.android.gamedriver.build_time is not set"); + String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME); + if (driverBuildTime == null || driverBuildTime.length() <= 1) { + Log.v(TAG, "com.android.graphics.driver.build_time is not set"); + driverBuildTime = "L0"; } // driver_build_time in the meta-data is in "L" format. e.g. L123456. // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly. @@ -901,7 +909,7 @@ public class GraphicsEnvironment { final Context driverContext = context.createPackageContext(driverPackageName, Context.CONTEXT_RESTRICTED); final BufferedReader reader = new BufferedReader(new InputStreamReader( - driverContext.getAssets().open(GAME_DRIVER_SPHAL_LIBRARIES_FILENAME))); + driverContext.getAssets().open(UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME))); final ArrayList assetStrings = new ArrayList<>(); for (String assetString; (assetString = reader.readLine()) != null;) { assetStrings.add(assetString); @@ -913,7 +921,7 @@ public class GraphicsEnvironment { } } catch (IOException e) { if (DEBUG) { - Log.w(TAG, "Failed to load '" + GAME_DRIVER_SPHAL_LIBRARIES_FILENAME + "'"); + Log.w(TAG, "Failed to load '" + UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME + "'"); } } return ""; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index c2c4d6266af68be19f19245f9966d11df4b2dc0e..8c2ca6d3e50918bd5552562b64bf0b088eb38c8b 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -946,7 +946,7 @@ public class Process { /** * Enable or disable the freezer. When enable == false all frozen processes are unfrozen, - * but aren't removed from the freezer. Processes can still be added or removed + * but aren't removed from the freezer. While in this state, processes can be added or removed * by using setProcessFrozen, but they won't actually be frozen until the freezer is enabled * again. If enable == true the freezer is enabled again, and all processes * in the freezer (including the ones added while the freezer was disabled) are frozen. diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java index e05991b33796a8eeb4beb61798c6f0bc3fe6693c..a79a1cfcd64ff4a82526a284e0c841437d066fc1 100644 --- a/core/java/android/os/storage/StorageManagerInternal.java +++ b/core/java/android/os/storage/StorageManagerInternal.java @@ -118,7 +118,7 @@ public abstract class StorageManagerInternal { * affects them. */ public abstract void onAppOpsChanged(int code, int uid, - @Nullable String packageName, int mode); + @Nullable String packageName, int mode, int previousMode); /** * Asks the StorageManager to reset all state for the provided user; this will result diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java index 8ad35e7eb37dfc6ae9740d264d6021962e243cb6..e2e61406ba95e8d264b5ae8a7eac211f81a455d6 100644 --- a/core/java/android/permission/PermissionControllerService.java +++ b/core/java/android/permission/PermissionControllerService.java @@ -35,6 +35,8 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.app.admin.DevicePolicyManager.PermissionGrantState; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -82,6 +84,15 @@ public abstract class PermissionControllerService extends Service { */ public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService"; + /** + * A ChangeId indicating that this device supports camera and mic indicators. Will be "false" + * if present, because the CompatChanges#isChangeEnabled method returns true if the change id + * is not present. + */ + @ChangeId + @Disabled + private static final long CAMERA_MIC_INDICATORS_NOT_PRESENT = 162547999L; + /** * Revoke a set of runtime permissions for various apps. * diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 1a59e8d34547bf249a3f3c5adcf49a98f6515b0a..b704d66d8e41c204572d8a425941c5eca63fa900 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -218,8 +218,15 @@ public abstract class DocumentsProvider extends ContentProvider { } /** {@hide} */ - private void enforceTree(Uri documentUri) { - if (isTreeUri(documentUri)) { + private void enforceTreeForExtraUris(Bundle extras) { + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + } + + /** {@hide} */ + private void enforceTree(@Nullable Uri documentUri) { + if (documentUri != null && isTreeUri(documentUri)) { final String parent = getTreeDocumentId(documentUri); final String child = getDocumentId(documentUri); if (Objects.equals(parent, child)) { @@ -232,6 +239,10 @@ public abstract class DocumentsProvider extends ContentProvider { } } + private Uri validateIncomingNullableUri(@Nullable Uri uri) { + return uri == null ? null : validateIncomingUri(uri); + } + /** * Create a new document and return its newly generated * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new @@ -1076,11 +1087,21 @@ public abstract class DocumentsProvider extends ContentProvider { final Context context = getContext(); final Bundle out = new Bundle(); + // If the URI is a tree URI performs some validation. + enforceTreeForExtraUris(extras); + + final Uri extraUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_URI)); + final Uri extraTargetUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + final Uri extraParentUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + if (METHOD_EJECT_ROOT.equals(method)) { // Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for // MANAGE_DOCUMENTS or associated URI permission here instead - final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri rootUri = extraUri; enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingAttributionTag(), null); @@ -1090,7 +1111,7 @@ public abstract class DocumentsProvider extends ContentProvider { return out; } - final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri documentUri = extraUri; final String authority = documentUri.getAuthority(); final String documentId = DocumentsContract.getDocumentId(documentUri); @@ -1099,14 +1120,11 @@ public abstract class DocumentsProvider extends ContentProvider { "Requested authority " + authority + " doesn't match provider " + mAuthority); } - // If the URI is a tree URI performs some validation. - enforceTree(documentUri); - if (METHOD_IS_CHILD_DOCUMENT.equals(method)) { enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingAttributionTag(), null); - final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri childUri = extraTargetUri; final String childAuthority = childUri.getAuthority(); final String childId = DocumentsContract.getDocumentId(childUri); @@ -1173,7 +1191,7 @@ public abstract class DocumentsProvider extends ContentProvider { revokeDocumentPermission(documentId); } else if (METHOD_COPY_DOCUMENT.equals(method)) { - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceReadPermissionInner(documentUri, getCallingPackage(), @@ -1197,9 +1215,9 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_MOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceWritePermissionInner(documentUri, getCallingPackage(), @@ -1225,7 +1243,7 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_REMOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); enforceReadPermissionInner(parentSourceUri, getCallingPackage(), diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a1d993bf1f34cceabcdaf5ca175b34eade1f987d..300bb7603722a3aa1935bb7e817162b76ce3cd94 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8941,6 +8941,13 @@ public final class Settings { */ public static final int ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW = 0x2; + /** + * Whether the Adaptive connectivity option is enabled. + * + * @hide + */ + public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. @@ -8956,6 +8963,22 @@ public final class Settings { ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES }; + /** + * How long Assistant handles have enabled in milliseconds. + * + * @hide + */ + public static final String ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS = + "reminder_exp_learning_time_elapsed"; + + /** + * How many times the Assistant has been triggered using the touch gesture. + * + * @hide + */ + public static final String ASSIST_HANDLES_LEARNING_EVENT_COUNT = + "reminder_exp_learning_event_count"; + /** * These entries are considered common between the personal and the managed profile, * since the managed profile doesn't get to change them. @@ -12263,63 +12286,71 @@ public final class Settings { "show_angle_in_use_dialog_box"; /** - * Game Driver global preference for all Apps. + * Updatable driver global preference for all Apps. * 0 = Default - * 1 = All Apps use Game Driver - * 2 = All Apps use system graphics driver + * 1 = All Apps use updatable production driver + * 2 = All apps use updatable prerelease driver + * 3 = All Apps use system graphics driver * @hide */ - public static final String GAME_DRIVER_ALL_APPS = "game_driver_all_apps"; + public static final String UPDATABLE_DRIVER_ALL_APPS = "updatable_driver_all_apps"; /** - * List of Apps selected to use Game Driver. + * List of Apps selected to use updatable production driver. * i.e. ,,..., * @hide */ - public static final String GAME_DRIVER_OPT_IN_APPS = "game_driver_opt_in_apps"; + public static final String UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS = + "updatable_driver_production_opt_in_apps"; /** - * List of Apps selected to use prerelease Game Driver. + * List of Apps selected to use updatable prerelease driver. * i.e. ,,..., * @hide */ - public static final String GAME_DRIVER_PRERELEASE_OPT_IN_APPS = - "game_driver_prerelease_opt_in_apps"; + public static final String UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS = + "updatable_driver_prerelease_opt_in_apps"; /** - * List of Apps selected not to use Game Driver. + * List of Apps selected not to use updatable production driver. * i.e. ,,..., * @hide */ - public static final String GAME_DRIVER_OPT_OUT_APPS = "game_driver_opt_out_apps"; + public static final String UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS = + "updatable_driver_production_opt_out_apps"; /** - * Apps on the denylist that are forbidden to use Game Driver. + * Apps on the denylist that are forbidden to use updatable production driver. * @hide */ - public static final String GAME_DRIVER_DENYLIST = "game_driver_denylist"; + public static final String UPDATABLE_DRIVER_PRODUCTION_DENYLIST = + "updatable_driver_production_denylist"; /** - * List of denylists, each denylist is a denylist for a specific version of Game Driver. + * List of denylists, each denylist is a denylist for a specific version of + * updatable production driver. * @hide */ - public static final String GAME_DRIVER_DENYLISTS = "game_driver_denylists"; + public static final String UPDATABLE_DRIVER_PRODUCTION_DENYLISTS = + "updatable_driver_production_denylists"; /** - * Apps on the allowlist that are allowed to use Game Driver. + * Apps on the allowlist that are allowed to use updatable production driver. * The string is a list of application package names, seperated by comma. * i.e. ,,..., * @hide */ - public static final String GAME_DRIVER_ALLOWLIST = "game_driver_allowlist"; + public static final String UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST = + "updatable_driver_production_allowlist"; /** - * List of libraries in sphal accessible by Game Driver + * List of libraries in sphal accessible by updatable driver * The string is a list of library names, separated by colon. * i.e. ::...: * @hide */ - public static final String GAME_DRIVER_SPHAL_LIBRARIES = "game_driver_sphal_libraries"; + public static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES = + "updatable_driver_sphal_libraries"; /** * Ordered GPU debug layer list for Vulkan diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java index 914169485979831e18c77339dad8f8c2e9188940..6eb2a15eec44b9c75a3f339ba4ee4eabc8f50956 100644 --- a/core/java/android/service/autofill/InlinePresentation.java +++ b/core/java/android/service/autofill/InlinePresentation.java @@ -40,6 +40,11 @@ public final class InlinePresentation implements Parcelable { /** * Represents the UI content and the action for the inline suggestion. + * + *

The Slice should be constructed using the Content builder provided in the androidx + * autofill library e.g. {@code androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder} + * and then converted to a Slice with + * {@code androidx.autofill.inline.UiVersions.Content#getSlice()}.

*/ private final @NonNull Slice mSlice; @@ -90,6 +95,11 @@ public final class InlinePresentation implements Parcelable { * * @param slice * Represents the UI content and the action for the inline suggestion. + * + *

The Slice should be constructed using the Content builder provided in the androidx + * autofill library e.g. {@code androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder} + * and then converted to a Slice with + * {@code androidx.autofill.inline.UiVersions.Content#getSlice()}.

* @param inlinePresentationSpec * Specifies the UI specification for the inline suggestion. * @param pinned @@ -118,6 +128,11 @@ public final class InlinePresentation implements Parcelable { /** * Represents the UI content and the action for the inline suggestion. + * + *

The Slice should be constructed using the Content builder provided in the androidx + * autofill library e.g. {@code androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder} + * and then converted to a Slice with + * {@code androidx.autofill.inline.UiVersions.Content#getSlice()}.

*/ @DataClass.Generated.Member public @NonNull Slice getSlice() { @@ -244,7 +259,7 @@ public final class InlinePresentation implements Parcelable { }; @DataClass.Generated( - time = 1593131904745L, + time = 1596484869201L, codegenVersion = "1.0.15", sourceFile = "frameworks/base/core/java/android/service/autofill/InlinePresentation.java", inputSignatures = "private final @android.annotation.NonNull android.app.slice.Slice mSlice\nprivate final @android.annotation.NonNull android.widget.inline.InlinePresentationSpec mInlinePresentationSpec\nprivate final boolean mPinned\npublic @android.annotation.NonNull @android.annotation.Size(min=0L) java.lang.String[] getAutofillHints()\nclass InlinePresentation extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)") diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 1d5f7fbb26413c98435e34228258118d17e887c7..ab1b943b8d6fcd095a4080ecb89bacbc3aa82b84 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1898,6 +1898,17 @@ public abstract class NotificationListenerService extends Service { mIsBubble = isBubble; } + /** + * @hide + */ + public @NonNull Ranking withAudiblyAlertedInfo(@Nullable Ranking previous) { + if (previous != null && previous.mLastAudiblyAlertedMs > 0 + && this.mLastAudiblyAlertedMs <= 0) { + this.mLastAudiblyAlertedMs = previous.mLastAudiblyAlertedMs; + } + return this; + } + /** * @hide */ diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index dee9ac4c2178ceccf7e0ca72664d19de26d1f52d..64364ffe98e01639cb9d31bad0a117a861ab576e 100644 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -62,17 +62,17 @@ import java.util.Set; * to release the native resources used by the TextToSpeech engine. * * Apps targeting Android 11 that use text-to-speech should declare {@link - * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the elements of their + * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their * manifest: * - * - * + *
+ * <queries>
  *   ...
- *  
- *      
- *  
- * 
- * 
+ *  <intent>
+ *      <action android:name="android.intent.action.TTS_SERVICE" />
+ *  </intent>
+ * </queries>
+ * 
*/ public class TextToSpeech { @@ -254,18 +254,17 @@ public class TextToSpeech { * * * Apps targeting Android 11 that use text-to-speech should declare {@link - * #INTENT_ACTION_TTS_SERVICE} in the elements of their + * TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE} in the {@code queries} elements of their * manifest: * - * - * + *
+     * <queries>
      *   ...
-     *  
-     *      
-     *  
-     * 
-     * 
-
+     *  <intent>
+     *      <action android:name="android.intent.action.TTS_SERVICE" />
+     *  </intent>
+     * </queries>
+     * 
*/ public class Engine { diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java index c726bee9f402d87bff6ce99cc2a25946596eb9ec..7c01f7a8739a2d8b28bedc39b260e5a704ef955b 100644 --- a/core/java/android/view/DisplayAdjustments.java +++ b/core/java/android/view/DisplayAdjustments.java @@ -130,14 +130,16 @@ public class DisplayAdjustments { w = metrics.noncompatWidthPixels; metrics.noncompatWidthPixels = metrics.noncompatHeightPixels; metrics.noncompatHeightPixels = w; + } - float x = metrics.xdpi; - metrics.xdpi = metrics.ydpi; - metrics.ydpi = x; - - x = metrics.noncompatXdpi; - metrics.noncompatXdpi = metrics.noncompatYdpi; - metrics.noncompatYdpi = x; + /** Adjusts global display metrics that is available to applications. */ + public void adjustGlobalAppMetrics(@NonNull DisplayMetrics metrics) { + final FixedRotationAdjustments rotationAdjustments = mFixedRotationAdjustments; + if (rotationAdjustments == null) { + return; + } + metrics.noncompatWidthPixels = metrics.widthPixels = rotationAdjustments.mAppWidth; + metrics.noncompatHeightPixels = metrics.heightPixels = rotationAdjustments.mAppHeight; } /** Returns the adjusted cutout if available. Otherwise the original cutout is returned. */ @@ -178,7 +180,7 @@ public class DisplayAdjustments { /** * An application can be launched in different rotation than the real display. This class - * provides the information to adjust the values returned by {@link #Display}. + * provides the information to adjust the values returned by {@link Display}. * @hide */ public static class FixedRotationAdjustments implements Parcelable { @@ -186,12 +188,24 @@ public class DisplayAdjustments { @Surface.Rotation final int mRotation; + /** + * The rotated {@link DisplayInfo#appWidth}. The value cannot be simply swapped according + * to rotation because it minus the region of screen decorations. + */ + final int mAppWidth; + + /** The rotated {@link DisplayInfo#appHeight}. */ + final int mAppHeight; + /** Non-null if the device has cutout. */ @Nullable final DisplayCutout mRotatedDisplayCutout; - public FixedRotationAdjustments(@Surface.Rotation int rotation, DisplayCutout cutout) { + public FixedRotationAdjustments(@Surface.Rotation int rotation, int appWidth, int appHeight, + DisplayCutout cutout) { mRotation = rotation; + mAppWidth = appWidth; + mAppHeight = appHeight; mRotatedDisplayCutout = cutout; } @@ -199,6 +213,8 @@ public class DisplayAdjustments { public int hashCode() { int hash = 17; hash = hash * 31 + mRotation; + hash = hash * 31 + mAppWidth; + hash = hash * 31 + mAppHeight; hash = hash * 31 + Objects.hashCode(mRotatedDisplayCutout); return hash; } @@ -210,12 +226,14 @@ public class DisplayAdjustments { } final FixedRotationAdjustments other = (FixedRotationAdjustments) o; return mRotation == other.mRotation + && mAppWidth == other.mAppWidth && mAppHeight == other.mAppHeight && Objects.equals(mRotatedDisplayCutout, other.mRotatedDisplayCutout); } @Override public String toString() { return "FixedRotationAdjustments{rotation=" + Surface.rotationToString(mRotation) + + " appWidth=" + mAppWidth + " appHeight=" + mAppHeight + " cutout=" + mRotatedDisplayCutout + "}"; } @@ -227,12 +245,16 @@ public class DisplayAdjustments { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mRotation); + dest.writeInt(mAppWidth); + dest.writeInt(mAppHeight); dest.writeTypedObject( new DisplayCutout.ParcelableWrapper(mRotatedDisplayCutout), flags); } private FixedRotationAdjustments(Parcel in) { mRotation = in.readInt(); + mAppWidth = in.readInt(); + mAppHeight = in.readInt(); final DisplayCutout.ParcelableWrapper cutoutWrapper = in.readTypedObject(DisplayCutout.ParcelableWrapper.CREATOR); mRotatedDisplayCutout = cutoutWrapper != null ? cutoutWrapper.get() : null; diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java index 713cfb48c95f13cda7e801c40b1b20ce9ad18b69..064bc6947fc43152044174f19727943150f5cd75 100644 --- a/core/java/android/view/FocusFinder.java +++ b/core/java/android/view/FocusFinder.java @@ -311,6 +311,9 @@ public class FocusFinder { } final int count = focusables.size(); + if (count < 2) { + return null; + } switch (direction) { case View.FOCUS_FORWARD: return getNextFocusable(focused, focusables, count); @@ -373,29 +376,29 @@ public class FocusFinder { } private static View getNextFocusable(View focused, ArrayList focusables, int count) { + if (count < 2) { + return null; + } if (focused != null) { int position = focusables.lastIndexOf(focused); if (position >= 0 && position + 1 < count) { return focusables.get(position + 1); } } - if (!focusables.isEmpty()) { - return focusables.get(0); - } - return null; + return focusables.get(0); } private static View getPreviousFocusable(View focused, ArrayList focusables, int count) { + if (count < 2) { + return null; + } if (focused != null) { int position = focusables.indexOf(focused); if (position > 0) { return focusables.get(position - 1); } } - if (!focusables.isEmpty()) { - return focusables.get(count - 1); - } - return null; + return focusables.get(count - 1); } private static View getNextKeyboardNavigationCluster( diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl index 429c3aeba9b3d2d16742dd688b7d222615b649c4..a0d4a6587bcffcb12ea62349c490cccd97a85446 100644 --- a/core/java/android/view/IDisplayWindowInsetsController.aidl +++ b/core/java/android/view/IDisplayWindowInsetsController.aidl @@ -26,6 +26,13 @@ import android.view.InsetsState; */ oneway interface IDisplayWindowInsetsController { + /** + * Called when top focused window changes to determine whether or not to take over insets + * control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false. + * @param packageName: Passes the top package name + */ + void topFocusedWindowChanged(String packageName); + /** * @see IWindow#insetsChanged */ diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 4aeb7bb71ce23763278751323a65e474f6fdc661..1bef2ee9ac73a94b808d9ea239940b98b6a14e5d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -387,16 +387,6 @@ interface IWindowManager */ oneway void hideTransientBars(int displayId); - /** - * When set to {@code true} the system bars will always be shown. This is true even if an app - * requests to be fullscreen by setting the system ui visibility flags. The - * functionality was added for the automotive case as a way to guarantee required content stays - * on screen at all times. - * - * @hide - */ - oneway void setForceShowSystemBars(boolean show); - /** * Called by System UI to notify of changes to the visibility of Recents. */ diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 985829f6c885d64c7b32ba99da78623e844fdcd0..403ac3ab29c0aa40e3d8c7814eac1e9460007be1 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -618,16 +618,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return false; } if (DEBUG) Log.d(TAG, "onStateChanged: " + state); - updateState(state); - - boolean localStateChanged = !mState.equals(mLastDispatchedState, - true /* excludingCaptionInsets */, true /* excludeInvisibleIme */); mLastDispatchedState.set(state, true /* copySources */); + final InsetsState lastState = new InsetsState(mState, true /* copySources */); + updateState(state); applyLocalVisibilityOverride(); - if (localStateChanged) { - if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState); + + if (!mState.equals(lastState, true /* excludingCaptionInsets */, + true /* excludeInvisibleIme */)) { + if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged"); mHost.notifyInsetsChanged(); + } + if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */, + true /* excludeInvisibleIme */)) { + if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState); updateRequestedState(); } return true; diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 6b0b509932a81b5a1fc30caf41d54a32dce067a7..81378831adbcee5ea8ab9b1f323d3a74b9b21a8d 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -60,6 +60,8 @@ import java.util.StringJoiner; */ public class InsetsState implements Parcelable { + public static final InsetsState EMPTY = new InsetsState(); + /** * Internal representation of inset source types. This is different from the public API in * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows @@ -74,6 +76,10 @@ public class InsetsState implements Parcelable { ITYPE_BOTTOM_GESTURES, ITYPE_LEFT_GESTURES, ITYPE_RIGHT_GESTURES, + ITYPE_TOP_MANDATORY_GESTURES, + ITYPE_BOTTOM_MANDATORY_GESTURES, + ITYPE_LEFT_MANDATORY_GESTURES, + ITYPE_RIGHT_MANDATORY_GESTURES, ITYPE_TOP_TAPPABLE_ELEMENT, ITYPE_BOTTOM_TAPPABLE_ELEMENT, ITYPE_LEFT_DISPLAY_CUTOUT, @@ -102,20 +108,27 @@ public class InsetsState implements Parcelable { public static final int ITYPE_BOTTOM_GESTURES = 4; public static final int ITYPE_LEFT_GESTURES = 5; public static final int ITYPE_RIGHT_GESTURES = 6; - public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 7; - public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 8; - public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 9; - public static final int ITYPE_TOP_DISPLAY_CUTOUT = 10; - public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 11; - public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 12; + /** Additional gesture inset types that map into {@link Type.MANDATORY_SYSTEM_GESTURES}. */ + public static final int ITYPE_TOP_MANDATORY_GESTURES = 7; + public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8; + public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9; + public static final int ITYPE_RIGHT_MANDATORY_GESTURES = 10; + + public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 11; + public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 12; + + public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 13; + public static final int ITYPE_TOP_DISPLAY_CUTOUT = 14; + public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 15; + public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 16; /** Input method window. */ - public static final int ITYPE_IME = 13; + public static final int ITYPE_IME = 17; /** Additional system decorations inset type. */ - public static final int ITYPE_CLIMATE_BAR = 14; - public static final int ITYPE_EXTRA_NAVIGATION_BAR = 15; + public static final int ITYPE_CLIMATE_BAR = 18; + public static final int ITYPE_EXTRA_NAVIGATION_BAR = 19; static final int LAST_TYPE = ITYPE_EXTRA_NAVIGATION_BAR; public static final int SIZE = LAST_TYPE + 1; @@ -451,9 +464,11 @@ public class InsetsState implements Parcelable { final ArraySet result = new ArraySet<>(); if ((types & Type.STATUS_BARS) != 0) { result.add(ITYPE_STATUS_BAR); + result.add(ITYPE_CLIMATE_BAR); } if ((types & Type.NAVIGATION_BARS) != 0) { result.add(ITYPE_NAVIGATION_BAR); + result.add(ITYPE_EXTRA_NAVIGATION_BAR); } if ((types & Type.CAPTION_BAR) != 0) { result.add(ITYPE_CAPTION_BAR); @@ -489,6 +504,10 @@ public class InsetsState implements Parcelable { return Type.IME; case ITYPE_TOP_GESTURES: case ITYPE_BOTTOM_GESTURES: + case ITYPE_TOP_MANDATORY_GESTURES: + case ITYPE_BOTTOM_MANDATORY_GESTURES: + case ITYPE_LEFT_MANDATORY_GESTURES: + case ITYPE_RIGHT_MANDATORY_GESTURES: return Type.MANDATORY_SYSTEM_GESTURES; case ITYPE_LEFT_GESTURES: case ITYPE_RIGHT_GESTURES: @@ -548,6 +567,14 @@ public class InsetsState implements Parcelable { return "ITYPE_LEFT_GESTURES"; case ITYPE_RIGHT_GESTURES: return "ITYPE_RIGHT_GESTURES"; + case ITYPE_TOP_MANDATORY_GESTURES: + return "ITYPE_TOP_MANDATORY_GESTURES"; + case ITYPE_BOTTOM_MANDATORY_GESTURES: + return "ITYPE_BOTTOM_MANDATORY_GESTURES"; + case ITYPE_LEFT_MANDATORY_GESTURES: + return "ITYPE_LEFT_MANDATORY_GESTURES"; + case ITYPE_RIGHT_MANDATORY_GESTURES: + return "ITYPE_RIGHT_MANDATORY_GESTURES"; case ITYPE_TOP_TAPPABLE_ELEMENT: return "ITYPE_TOP_TAPPABLE_ELEMENT"; case ITYPE_BOTTOM_TAPPABLE_ELEMENT: diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index f777f5518da6fc8a0d8ac0704b30d8308e21261b..cf96192c2a205cec89b5f683f44aef12ec989d0f 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -99,7 +99,7 @@ public class ViewConfiguration { * Defines the duration in milliseconds a user needs to hold down the * appropriate buttons (power + volume down) to trigger the screenshot chord. */ - private static final int SCREENSHOT_CHORD_KEY_TIMEOUT = 500; + private static final int SCREENSHOT_CHORD_KEY_TIMEOUT = 0; /** * Defines the duration in milliseconds a user needs to hold down the diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 994a959836738070d4f26f9ea190afc7ae5565c7..819462190d9c5922931c2426eee2a6bee818d11f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -53,6 +53,9 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CO import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FIT_INSETS_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; @@ -1449,14 +1452,13 @@ public final class ViewRootImpl implements ViewParent, } // Don't lose the mode we last auto-computed. - if ((attrs.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) + if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST) == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode - & ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) - | (oldSoftInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST); + & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST); } - if ((changes & LayoutParams.SOFT_INPUT_MODE_CHANGED) != 0) { + if (mWindowAttributes.softInputMode != oldSoftInputMode) { requestFitSystemWindows(); } @@ -1979,11 +1981,7 @@ public final class ViewRootImpl implements ViewParent, mCompatibleVisibilityInfo.globalVisibility = (mCompatibleVisibilityInfo.globalVisibility & ~View.SYSTEM_UI_FLAG_LOW_PROFILE) | (mAttachInfo.mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE); - if (mDispatchedSystemUiVisibility != mCompatibleVisibilityInfo.globalVisibility) { - mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY); - mHandler.sendMessage(mHandler.obtainMessage( - MSG_DISPATCH_SYSTEM_UI_VISIBILITY, mCompatibleVisibilityInfo)); - } + dispatchDispatchSystemUiVisibilityChanged(mCompatibleVisibilityInfo); if (mAttachInfo.mKeepScreenOn != oldScreenOn || mAttachInfo.mSystemUiVisibility != params.subtreeSystemUiVisibility || mAttachInfo.mHasSystemUiListeners != params.hasSystemUiListeners) { @@ -2037,9 +2035,30 @@ public final class ViewRootImpl implements ViewParent, info.globalVisibility |= systemUiFlag; info.localChanges &= ~systemUiFlag; } - if (mDispatchedSystemUiVisibility != info.globalVisibility) { + dispatchDispatchSystemUiVisibilityChanged(info); + } + + /** + * If the system is forcing showing any system bar, the legacy low profile flag should be + * cleared for compatibility. + * + * @param showTypes {@link InsetsType types} shown by the system. + * @param fromIme {@code true} if the invocation is from IME. + */ + private void clearLowProfileModeIfNeeded(@InsetsType int showTypes, boolean fromIme) { + final SystemUiVisibilityInfo info = mCompatibleVisibilityInfo; + if ((showTypes & Type.systemBars()) != 0 && !fromIme + && (info.globalVisibility & SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { + info.globalVisibility &= ~SYSTEM_UI_FLAG_LOW_PROFILE; + info.localChanges |= SYSTEM_UI_FLAG_LOW_PROFILE; + dispatchDispatchSystemUiVisibilityChanged(info); + } + } + + private void dispatchDispatchSystemUiVisibilityChanged(SystemUiVisibilityInfo args) { + if (mDispatchedSystemUiVisibility != args.globalVisibility) { mHandler.removeMessages(MSG_DISPATCH_SYSTEM_UI_VISIBILITY); - mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, info)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args)); } } @@ -2073,6 +2092,7 @@ public final class ViewRootImpl implements ViewParent, final int sysUiVis = inOutParams.systemUiVisibility | inOutParams.subtreeSystemUiVisibility; final int flags = inOutParams.flags; final int type = inOutParams.type; + final int adjust = inOutParams.softInputMode & SOFT_INPUT_MASK_ADJUST; if ((inOutParams.privateFlags & PRIVATE_FLAG_APPEARANCE_CONTROLLED) == 0) { inOutParams.insetsFlags.appearance = 0; @@ -2098,12 +2118,13 @@ public final class ViewRootImpl implements ViewParent, } } + inOutParams.privateFlags &= ~PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; + if ((inOutParams.privateFlags & PRIVATE_FLAG_FIT_INSETS_CONTROLLED) != 0) { return; } int types = inOutParams.getFitInsetsTypes(); - int sides = inOutParams.getFitInsetsSides(); boolean ignoreVis = inOutParams.isFitInsetsIgnoringVisibility(); if (((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0 @@ -2118,10 +2139,13 @@ public final class ViewRootImpl implements ViewParent, if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { ignoreVis = true; } else if ((types & Type.systemBars()) == Type.systemBars()) { - types |= Type.ime(); + if (adjust == SOFT_INPUT_ADJUST_RESIZE) { + types |= Type.ime(); + } else { + inOutParams.privateFlags |= PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; + } } inOutParams.setFitInsetsTypes(types); - inOutParams.setFitInsetsSides(sides); inOutParams.setFitInsetsIgnoringVisibility(ignoreVis); // The fitting of insets are not really controlled by the clients, so we remove the flag. @@ -2491,8 +2515,7 @@ public final class ViewRootImpl implements ViewParent, if (mFirst || mAttachInfo.mViewVisibilityChanged) { mAttachInfo.mViewVisibilityChanged = false; - int resizeMode = mSoftInputMode & - WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; + int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST; // If we are in auto resize mode, then we need to determine // what mode to use now. if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) { @@ -2505,11 +2528,8 @@ public final class ViewRootImpl implements ViewParent, if (resizeMode == 0) { resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; } - if ((lp.softInputMode & - WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != resizeMode) { - lp.softInputMode = (lp.softInputMode & - ~WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) | - resizeMode; + if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) { + lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode; params = lp; } } @@ -5005,6 +5025,7 @@ public final class ViewRootImpl implements ViewParent, String.format("Calling showInsets(%d,%b) on window that no longer" + " has views.", msg.arg1, msg.arg2 == 1)); } + clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1); mInsetsController.show(msg.arg1, msg.arg2 == 1); break; } diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 1a9003581078924c1a57646b80618ea200d70103..24538c5205b01f0d18cbd7ff811a2cbc014c6b38 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -33,7 +33,6 @@ import java.lang.annotation.RetentionPolicy; /** * Interface to control windows that generate insets. * - * TODO(118118435): Needs more information and examples once the API is more baked. */ public interface WindowInsetsController { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 4567cc96cbb7585d8c146785680da677c7d4ab0f..c356769a73b3efdac73cf9dfe5f2e9f4bb7d3cd6 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2033,6 +2033,12 @@ public interface WindowManager extends ViewManager { */ public static final int PRIVATE_FLAG_FIT_INSETS_CONTROLLED = 0x10000000; + /** + * Flag to indicate that the parent frame of a window should be inset by IME. + * @hide + */ + public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000; + /** * An internal annotation for flags that can be specified to {@link #softInputMode}. * diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java index 492ab6f8a3d575ad75467a2151ce0c29af6824ad..8c355202b63f1485a0a37dfdaac83c6e2ff46c7b 100644 --- a/core/java/android/view/WindowManagerPolicyConstants.java +++ b/core/java/android/view/WindowManagerPolicyConstants.java @@ -49,6 +49,13 @@ public interface WindowManagerPolicyConstants { int PRESENCE_INTERNAL = 1 << 0; int PRESENCE_EXTERNAL = 1 << 1; + // Alternate bars position values + int ALT_BAR_UNKNOWN = -1; + int ALT_BAR_LEFT = 1 << 0; + int ALT_BAR_RIGHT = 1 << 1; + int ALT_BAR_BOTTOM = 1 << 2; + int ALT_BAR_TOP = 1 << 3; + // Navigation bar position values int NAV_BAR_INVALID = -1; int NAV_BAR_LEFT = 1 << 0; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b1f4df143a0f78cf8d7d451c9096d359bc706d2e..2ed0b766b69ef2dd914018ab06009a8225f7024d 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -611,7 +611,8 @@ public final class InputMethodManager { @Override public void startInputAsyncOnWindowFocusGain(View focusedView, @SoftInputModeFlags int softInputMode, int windowFlags, boolean forceNewFocus) { - final int startInputFlags = getStartInputFlags(focusedView, 0); + int startInputFlags = getStartInputFlags(focusedView, 0); + startInputFlags |= StartInputFlags.WINDOW_GAINED_FOCUS; final ImeFocusController controller = getFocusController(); if (controller == null) { diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 0eed7b6af43c9cb39af905c9398ffe55a631d76e..3dc925df86581908d3133daf663bdbc1c070398c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -387,6 +387,7 @@ public class Editor { private final SuggestionHelper mSuggestionHelper = new SuggestionHelper(); private boolean mFlagCursorDragFromAnywhereEnabled; + private float mCursorDragDirectionMinXYRatio; private boolean mFlagInsertionHandleGesturesEnabled; // Specifies whether the new magnifier (with fish-eye effect) is enabled. @@ -423,6 +424,11 @@ public class Editor { mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting( WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0; + final int cursorDragMinAngleFromVertical = AppGlobals.getIntCoreSetting( + WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL, + WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT); + mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio( + cursorDragMinAngleFromVertical); mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting( WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES, WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0; @@ -432,6 +438,8 @@ public class Editor { if (TextView.DEBUG_CURSOR) { logCursor("Editor", "Cursor drag from anywhere is %s.", mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled"); + logCursor("Editor", "Cursor drag min angle from vertical is %d (= %f x/y ratio)", + cursorDragMinAngleFromVertical, mCursorDragDirectionMinXYRatio); logCursor("Editor", "Insertion handle gestures is %s.", mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled"); logCursor("Editor", "New magnifier is %s.", @@ -457,6 +465,11 @@ public class Editor { mFlagCursorDragFromAnywhereEnabled = enabled; } + @VisibleForTesting + public void setCursorDragMinAngleFromVertical(int degreesFromVertical) { + mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(degreesFromVertical); + } + @VisibleForTesting public boolean getFlagInsertionHandleGesturesEnabled() { return mFlagInsertionHandleGesturesEnabled; @@ -6059,12 +6072,7 @@ public class Editor { return trueLine; } - final int lineHeight = layout.getLineBottom(prevLine) - layout.getLineTop(prevLine); - int slop = (int)(LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS - * (layout.getLineBottom(trueLine) - layout.getLineTop(trueLine))); - slop = Math.max(mLineChangeSlopMin, - Math.min(mLineChangeSlopMax, lineHeight + slop)) - lineHeight; - slop = Math.max(0, slop); + final int slop = (int)(LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS * mTextView.getLineHeight()); final float verticalOffset = mTextView.viewportToContentVerticalOffset(); if (trueLine > prevLine && y >= layout.getLineBottom(prevLine) + slop + verticalOffset) { @@ -6134,10 +6142,11 @@ public class Editor { if (mIsDraggingCursor) { performCursorDrag(event); } else if (mFlagCursorDragFromAnywhereEnabled - && mTextView.getLayout() != null - && mTextView.isFocused() - && mTouchState.isMovedEnoughForDrag() - && !mTouchState.isDragCloseToVertical()) { + && mTextView.getLayout() != null + && mTextView.isFocused() + && mTouchState.isMovedEnoughForDrag() + && (mTouchState.getInitialDragDirectionXYRatio() + > mCursorDragDirectionMinXYRatio || mTouchState.isOnHandle())) { startCursorDrag(event); } break; diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java index 9eb63087a66eb3b8353b7a01f2ab50ba829edd44..751436865ff5348cdcfa3dc4f44b560bbc00c27c 100644 --- a/core/java/android/widget/EditorTouchState.java +++ b/core/java/android/widget/EditorTouchState.java @@ -59,7 +59,7 @@ public class EditorTouchState { private boolean mMultiTapInSameArea; private boolean mMovedEnoughForDrag; - private boolean mIsDragCloseToVertical; + private float mInitialDragDirectionXYRatio; public float getLastDownX() { return mLastDownX; @@ -98,8 +98,23 @@ public class EditorTouchState { return mMovedEnoughForDrag; } - public boolean isDragCloseToVertical() { - return mIsDragCloseToVertical && !mIsOnHandle; + /** + * When {@link #isMovedEnoughForDrag()} is {@code true}, this function returns the x/y ratio for + * the initial drag direction. Smaller values indicate that the direction is closer to vertical, + * while larger values indicate that the direction is closer to horizontal. For example: + *
    + *
  • if the drag direction is exactly vertical, this returns 0 + *
  • if the drag direction is exactly horizontal, this returns {@link Float#MAX_VALUE} + *
  • if the drag direction is 45 deg from vertical, this returns 1 + *
  • if the drag direction is 30 deg from vertical, this returns 0.58 (x delta is smaller + * than y delta) + *
  • if the drag direction is 60 deg from vertical, this returns 1.73 (x delta is bigger + * than y delta) + *
+ * This function never returns negative values, regardless of the direction of the drag. + */ + public float getInitialDragDirectionXYRatio() { + return mInitialDragDirectionXYRatio; } public void setIsOnHandle(boolean onHandle) { @@ -155,7 +170,7 @@ public class EditorTouchState { mLastDownY = event.getY(); mLastDownMillis = event.getEventTime(); mMovedEnoughForDrag = false; - mIsDragCloseToVertical = false; + mInitialDragDirectionXYRatio = 0.0f; } else if (action == MotionEvent.ACTION_UP) { if (TextView.DEBUG_CURSOR) { logCursor("EditorTouchState", "ACTION_UP"); @@ -164,7 +179,7 @@ public class EditorTouchState { mLastUpY = event.getY(); mLastUpMillis = event.getEventTime(); mMovedEnoughForDrag = false; - mIsDragCloseToVertical = false; + mInitialDragDirectionXYRatio = 0.0f; } else if (action == MotionEvent.ACTION_MOVE) { if (!mMovedEnoughForDrag) { float deltaX = event.getX() - mLastDownX; @@ -174,9 +189,8 @@ public class EditorTouchState { int touchSlop = config.getScaledTouchSlop(); mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop; if (mMovedEnoughForDrag) { - // If the direction of the swipe motion is within 45 degrees of vertical, it is - // considered a vertical drag. - mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY); + mInitialDragDirectionXYRatio = (deltaY == 0) ? Float.MAX_VALUE : + Math.abs(deltaX / deltaY); } } } else if (action == MotionEvent.ACTION_CANCEL) { @@ -185,7 +199,7 @@ public class EditorTouchState { mMultiTapStatus = MultiTapStatus.NONE; mMultiTapInSameArea = false; mMovedEnoughForDrag = false; - mIsDragCloseToVertical = false; + mInitialDragDirectionXYRatio = 0.0f; } } @@ -201,4 +215,27 @@ public class EditorTouchState { float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY); return distanceSquared <= maxDistance * maxDistance; } + + /** + * Returns the x/y ratio corresponding to the given angle relative to vertical. Smaller angle + * values (ie, closer to vertical) will result in a smaller x/y ratio. For example: + *
    + *
  • if the angle is 45 deg, the ratio is 1 + *
  • if the angle is 30 deg, the ratio is 0.58 (x delta is smaller than y delta) + *
  • if the angle is 60 deg, the ratio is 1.73 (x delta is bigger than y delta) + *
+ * If the passed-in value is <= 0, this function returns 0. If the passed-in value is >= 90, + * this function returns {@link Float#MAX_VALUE}. + * + * @see #getInitialDragDirectionXYRatio() + */ + public static float getXYRatio(int angleFromVerticalInDegrees) { + if (angleFromVerticalInDegrees <= 0) { + return 0.0f; + } + if (angleFromVerticalInDegrees >= 90) { + return Float.MAX_VALUE; + } + return (float) Math.tan(Math.toRadians(angleFromVerticalInDegrees)); + } } diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index 8de9149a404c5ba70f657ba25ce27d9bf28eeb23..3c45e8c5d78b0fecf8595854d393da59740dabbc 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -54,6 +54,7 @@ import android.view.View; import android.view.ViewDebug; import android.view.ViewHierarchyEncoder; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; @@ -310,9 +311,6 @@ public class ProgressBar extends View { setMax(a.getInt(R.styleable.ProgressBar_max, mMax)); setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress)); - // onProgressRefresh() is only called when the progress changes. So we should set - // stateDescription during initialization here. - super.setStateDescription(formatStateDescription(mProgress)); setSecondaryProgress(a.getInt( R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress)); @@ -1616,7 +1614,8 @@ public class ProgressBar extends View { } void onProgressRefresh(float scale, boolean fromUser, int progress) { - if (mCustomStateDescription == null) { + if (AccessibilityManager.getInstance(mContext).isEnabled() + && mCustomStateDescription == null) { super.setStateDescription(formatStateDescription(mProgress)); } } @@ -2340,6 +2339,7 @@ public class ProgressBar extends View { AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(), getProgress()); info.setRangeInfo(rangeInfo); + info.setStateDescription(formatStateDescription(mProgress)); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index c617ccca516efd85b42b6981a94ab069066874fc..deed219135ad33619c0614e1ec1724b097d70712 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -395,6 +395,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private static final int EMS = LINES; private static final int PIXELS = 2; + // Maximum text length for single line input. + private static final int MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT = 5000; + private InputFilter.LengthFilter mSingleLineLengthFilter = null; + private static final RectF TEMP_RECTF = new RectF(); /** @hide */ @@ -1589,7 +1593,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Same as setSingleLine(), but make sure the transformation method and the maximum number // of lines of height are unchanged for multi-line TextViews. setInputTypeSingleLine(singleLine); - applySingleLine(singleLine, singleLine, singleLine); + applySingleLine(singleLine, singleLine, singleLine, + // Does not apply automated max length filter since length filter will be resolved + // later in this function. + false + ); if (singleLine && getKeyListener() == null && ellipsize == ELLIPSIZE_NOT_SET) { ellipsize = ELLIPSIZE_END; @@ -1633,7 +1641,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setTransformationMethod(PasswordTransformationMethod.getInstance()); } - if (maxlength >= 0) { + // For addressing b/145128646 + // For the performance reason, we limit characters for single line text field. + if (bufferType == BufferType.EDITABLE && singleLine && maxlength == -1) { + mSingleLineLengthFilter = new InputFilter.LengthFilter( + MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT); + } + + if (mSingleLineLengthFilter != null) { + setFilters(new InputFilter[] { mSingleLineLengthFilter }); + } else if (maxlength >= 0) { setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) }); } else { setFilters(NO_FILTERS); @@ -6590,7 +6607,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mSingleLine != singleLine || forceUpdate) { // Change single line mode, but only change the transformation if // we are not in password mode. - applySingleLine(singleLine, !isPassword, true); + applySingleLine(singleLine, !isPassword, true, true); } if (!isSuggestionsEnabled()) { @@ -10229,6 +10246,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Note that the default conditions are not necessarily those that were in effect prior this * method, and you may want to reset these properties to your custom values. * + * Note that due to performance reasons, by setting single line for the EditText, the maximum + * text length is set to 5000 if no other character limitation are applied. + * * @attr ref android.R.styleable#TextView_singleLine */ @android.view.RemotableViewMethod @@ -10236,7 +10256,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Could be used, but may break backward compatibility. // if (mSingleLine == singleLine) return; setInputTypeSingleLine(singleLine); - applySingleLine(singleLine, true, true); + applySingleLine(singleLine, true, true, true); } /** @@ -10256,14 +10276,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } private void applySingleLine(boolean singleLine, boolean applyTransformation, - boolean changeMaxLines) { + boolean changeMaxLines, boolean changeMaxLength) { mSingleLine = singleLine; + if (singleLine) { setLines(1); setHorizontallyScrolling(true); if (applyTransformation) { setTransformationMethod(SingleLineTransformationMethod.getInstance()); } + + if (!changeMaxLength) return; + + // Single line length filter is only applicable editable text. + if (mBufferType != BufferType.EDITABLE) return; + + final InputFilter[] prevFilters = getFilters(); + for (InputFilter filter: getFilters()) { + // We don't add LengthFilter if already there. + if (filter instanceof InputFilter.LengthFilter) return; + } + + if (mSingleLineLengthFilter == null) { + mSingleLineLengthFilter = new InputFilter.LengthFilter( + MAX_LENGTH_FOR_SINGLE_LINE_EDIT_TEXT); + } + + final InputFilter[] newFilters = new InputFilter[prevFilters.length + 1]; + System.arraycopy(prevFilters, 0, newFilters, 0, prevFilters.length); + newFilters[prevFilters.length] = mSingleLineLengthFilter; + + setFilters(newFilters); + + // Since filter doesn't apply to existing text, trigger filter by setting text. + setText(getText()); } else { if (changeMaxLines) { setMaxLines(Integer.MAX_VALUE); @@ -10272,6 +10318,47 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (applyTransformation) { setTransformationMethod(null); } + + if (!changeMaxLength) return; + + // Single line length filter is only applicable editable text. + if (mBufferType != BufferType.EDITABLE) return; + + final InputFilter[] prevFilters = getFilters(); + if (prevFilters.length == 0) return; + + // Short Circuit: if mSingleLineLengthFilter is not allocated, nobody sets automated + // single line char limit filter. + if (mSingleLineLengthFilter == null) return; + + // If we need to remove mSingleLineLengthFilter, we need to allocate another array. + // Since filter list is expected to be small and want to avoid unnecessary array + // allocation, check if there is mSingleLengthFilter first. + int targetIndex = -1; + for (int i = 0; i < prevFilters.length; ++i) { + if (prevFilters[i] == mSingleLineLengthFilter) { + targetIndex = i; + break; + } + } + if (targetIndex == -1) return; // not found. Do nothing. + + if (prevFilters.length == 1) { + setFilters(NO_FILTERS); + return; + } + + // Create new array which doesn't include mSingleLengthFilter. + final InputFilter[] newFilters = new InputFilter[prevFilters.length - 1]; + System.arraycopy(prevFilters, 0, newFilters, 0, targetIndex); + System.arraycopy( + prevFilters, + targetIndex + 1, + newFilters, + targetIndex, + prevFilters.length - targetIndex - 1); + setFilters(newFilters); + mSingleLineLengthFilter = null; } } diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java index 09ab5aa17782e19d53a7c036838727401a7da9e2..e272086a53ea46e370377de7dd6e56da519ac42a 100644 --- a/core/java/android/widget/WidgetFlags.java +++ b/core/java/android/widget/WidgetFlags.java @@ -40,6 +40,28 @@ public final class WidgetFlags { */ public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true; + /** + * Threshold for the direction of a swipe gesture in order for it to be handled as a cursor drag + * rather than a scroll. The direction angle of the swipe gesture must exceed this value in + * order to trigger cursor drag; otherwise, the swipe will be assumed to be a scroll gesture. + * The value units for this flag is degrees and the valid range is [0,90] inclusive. If a value + * < 0 is set, 0 will be used instead; if a value > 90 is set, 90 will be used instead. + */ + public static final String CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL = + "CursorControlFeature__min_angle_from_vertical_to_start_cursor_drag"; + + /** + * The key used in app core settings for the flag + * {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}. + */ + public static final String KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL = + "widget__min_angle_from_vertical_to_start_cursor_drag"; + + /** + * Default value for the flag {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}. + */ + public static final int CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT = 45; + /** * The flag of finger-to-cursor distance in DP for cursor dragging. * The value unit is DP and the range is {0..100}. If the value is out of range, the legacy diff --git a/core/java/android/widget/inline/InlinePresentationSpec.java b/core/java/android/widget/inline/InlinePresentationSpec.java index 5f924c6ae194afc8daaa2c408905d2254cd1a33b..e7727fd9ff1d196d596578e239d0ceee3a4b001d 100644 --- a/core/java/android/widget/inline/InlinePresentationSpec.java +++ b/core/java/android/widget/inline/InlinePresentationSpec.java @@ -42,8 +42,13 @@ public final class InlinePresentationSpec implements Parcelable { private final Size mMaxSize; /** - * The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case - * the default system UI style will be used. + * The extras encoding the UI style information. + * + *

The style bundles can be created using the relevant Style classes and their builders in + * the androidx autofill library e.g. {@code androidx.autofill.inline.UiVersions.StylesBuilder}. + *

+ * + *

The style must be set for the suggestion to render properly.

* *

Note: There should be no remote objects in the bundle, all included remote objects will * be removed from the bundle before transmission.

@@ -123,8 +128,13 @@ public final class InlinePresentationSpec implements Parcelable { } /** - * The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case - * the default system UI style will be used. + * The extras encoding the UI style information. + * + *

The style bundles can be created using the relevant Style classes and their builders in + * the androidx autofill library e.g. {@code androidx.autofill.inline.UiVersions.StylesBuilder}. + *

+ * + *

The style must be set for the suggestion to render properly.

* *

Note: There should be no remote objects in the bundle, all included remote objects will * be removed from the bundle before transmission.

@@ -264,8 +274,13 @@ public final class InlinePresentationSpec implements Parcelable { } /** - * The extras encoding the UI style information. Defaults to {@code Bundle.Empty} in which case - * the default system UI style will be used. + * The extras encoding the UI style information. + * + *

The style bundles can be created using the relevant Style classes and their builders in + * the androidx autofill library e.g. {@code androidx.autofill.inline.UiVersions.StylesBuilder}. + *

+ * + *

The style must be set for the suggestion to render properly.

* *

Note: There should be no remote objects in the bundle, all included remote objects will * be removed from the bundle before transmission.

@@ -302,7 +317,7 @@ public final class InlinePresentationSpec implements Parcelable { } @DataClass.Generated( - time = 1588109681295L, + time = 1596485189661L, codegenVersion = "1.0.15", sourceFile = "frameworks/base/core/java/android/widget/inline/InlinePresentationSpec.java", inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nprivate final @android.annotation.NonNull android.os.Bundle mStyle\nprivate static @android.annotation.NonNull android.os.Bundle defaultStyle()\nprivate boolean styleEquals(android.os.Bundle)\npublic void filterContentTypes()\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []") diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java index 9ccb4c172158d5678523dc339f55e051ae97b88f..9013da36007e4f81c81a3f45c4de40580e927642 100644 --- a/core/java/android/window/VirtualDisplayTaskEmbedder.java +++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java @@ -19,6 +19,7 @@ package android.window; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.view.Display.INVALID_DISPLAY; import android.app.ActivityManager; @@ -63,6 +64,7 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { private int mDisplayDensityDpi; private final boolean mSingleTaskInstance; private final boolean mUsePublicVirtualDisplay; + private final boolean mUseTrustedDisplay; private VirtualDisplay mVirtualDisplay; private Insets mForwardedInsets; private DisplayMetrics mTmpDisplayMetrics; @@ -77,10 +79,12 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { * only applicable if virtual displays are used */ public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host, - boolean singleTaskInstance, boolean usePublicVirtualDisplay) { + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean useTrustedDisplay) { super(context, host); mSingleTaskInstance = singleTaskInstance; mUsePublicVirtualDisplay = usePublicVirtualDisplay; + mUseTrustedDisplay = useTrustedDisplay; } /** @@ -103,6 +107,9 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { if (mUsePublicVirtualDisplay) { virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_PUBLIC; } + if (mUseTrustedDisplay) { + virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_TRUSTED; + } mVirtualDisplay = displayManager.createVirtualDisplay( DISPLAY_NAME + "@" + System.identityHashCode(this), mHost.getWidth(), diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 236e67a1ea70de99e5fcf1e4ba9128e883863364..ac8f9e8424b7818415c44074cfb07b2818f6c11a 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -273,8 +273,6 @@ public class ChooserActivity extends ResolverActivity implements private int mLastNumberOfChildren = -1; private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment"; - // TODO: Update to handle landscape instead of using static value - private static final int MAX_RANKED_TARGETS = 4; private final List mServiceConnections = new ArrayList<>(); private final Set> mServicesRequested = new HashSet<>(); @@ -784,8 +782,8 @@ public class ChooserActivity extends ResolverActivity implements FrameworkStatsLog.SHARESHEET_STARTED, getReferrerPackageName(), target.getType(), - initialIntents == null ? 0 : initialIntents.length, mCallerChooserTargets == null ? 0 : mCallerChooserTargets.length, + initialIntents == null ? 0 : initialIntents.length, isWorkProfile(), findPreferredContentPreview(getTargetIntent(), getContentResolver()), target.getAction() @@ -2641,7 +2639,10 @@ public class ChooserActivity extends ResolverActivity implements } RecyclerView recyclerView = mChooserMultiProfilePagerAdapter.getActiveAdapterView(); ChooserGridAdapter gridAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter(); - if (gridAdapter == null || recyclerView == null) { + // Skip height calculation if recycler view was scrolled to prevent it inaccurately + // calculating the height, as the logic below does not account for the scrolled offset. + if (gridAdapter == null || recyclerView == null + || recyclerView.computeVerticalScrollOffset() != 0) { return; } @@ -3128,6 +3129,13 @@ public class ChooserActivity extends ResolverActivity implements ChooserGridAdapter currentRootAdapter = mChooserMultiProfilePagerAdapter.getCurrentRootAdapter(); currentRootAdapter.updateDirectShareExpansion(); + // This fixes an edge case where after performing a variety of gestures, vertical scrolling + // ends up disabled. That's because at some point the old tab's vertical scrolling is + // disabled and the new tab's is enabled. For context, see b/159997845 + setVerticalScrollEnabled(true); + if (mResolverDrawerLayout != null) { + mResolverDrawerLayout.scrollNestedScrollableChildBackToTop(); + } } @Override @@ -3286,9 +3294,8 @@ public class ChooserActivity extends ResolverActivity implements } /** - * Returns either {@code 0} or {@code 1} depending on whether we want to show the list item - * content preview. Not to be confused with the sticky content preview which is above the - * personal and work tabs. + * Whether the "system" row of targets is displayed. + * This area includes the content preview (if present) and action row. */ public int getSystemRowCount() { // For the tabbed case we show the sticky content preview above the tabs, @@ -3296,6 +3303,7 @@ public class ChooserActivity extends ResolverActivity implements if (shouldShowTabs()) { return 0; } + if (!isSendAction(getTargetIntent())) { return 0; } diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java index ffa6041721c6f5e34479ca674da65d6f2b24e2e5..3a65a324f9d6cbf8fa556b33beb64b4926b003cc 100644 --- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java +++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java @@ -252,8 +252,10 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd @Override protected void setupContainerPadding(View container) { + int initialBottomPadding = getContext().getResources().getDimensionPixelSize( + R.dimen.resolver_empty_state_container_padding_bottom); container.setPadding(container.getPaddingLeft(), container.getPaddingTop(), - container.getPaddingRight(), container.getPaddingBottom() + mBottomOffset); + container.getPaddingRight(), initialBottomPadding + mBottomOffset); } class ChooserProfileDescriptor extends ProfileDescriptor { diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index d238d0eb916d5cea1e912b144839eae979faa45d..b4cd145ca374cfbda7734e5bbbf9f1215be2ffbc 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -120,6 +120,18 @@ public final class SystemUiDeviceConfigFlags { */ public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days"; + // Flag related to Privacy Indicators + + /** + * Whether to show the complete ongoing app ops chip. + */ + public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled"; + + /** + * Whether to show app ops chip for just microphone + camera. + */ + public static final String PROPERTY_MIC_CAMERA_ENABLED = "camera_mic_icons_enabled"; + // Flags related to Assistant /** @@ -377,6 +389,20 @@ public final class SystemUiDeviceConfigFlags { */ public static final String CHOOSER_TARGET_RANKING_ENABLED = "chooser_target_ranking_enabled"; + /** + * (float) Weight bonus applied on top sharing shortcuts as per native ranking provided by apps. + * Its range need to be 0 ~ 1. + */ + public static final String TOP_NATIVE_RANKED_SHARING_SHORTCUTS_BOOSTER = + "top_native_ranked_sharing_shortcut_booster"; + + /** + * (float) Weight bonus applied on 2nd top sharing shortcuts as per native ranking provided by + * apps. Its range need to be 0 ~ 1. + */ + public static final String NON_TOP_NATIVE_RANKED_SHARING_SHORTCUTS_BOOSTER = + "non_top_native_ranked_sharing_shortcut_booster"; + /** * (boolean) Whether to enable user-drag resizing for PIP. */ @@ -397,6 +423,11 @@ public final class SystemUiDeviceConfigFlags { */ public static final String BACK_GESTURE_SLOP_MULTIPLIER = "back_gesture_slop_multiplier"; + /** + * (long) Screenshot keychord delay (how long the buttons must be pressed), in ms + */ + public static final String SCREENSHOT_KEYCHORD_DELAY = "screenshot_keychord_delay"; + private SystemUiDeviceConfigFlags() { } } diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index a50a52219c742a8850411817b11431e94f05465f..3b5fecfc600aeb7946613bee63d60bb36c5c0c84 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -113,6 +113,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { // Default is no-op } + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -283,6 +291,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String afterDocId = getDocIdForFile(after); onDocIdChanged(docId); + onDocIdDeleted(docId); onDocIdChanged(afterDocId); final File afterVisibleFile = getFileForDocId(afterDocId, true); @@ -312,6 +321,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String docId = getDocIdForFile(after); onDocIdChanged(sourceDocumentId); + onDocIdDeleted(sourceDocumentId); onDocIdChanged(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); @@ -343,6 +353,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } onDocIdChanged(docId); + onDocIdDeleted(docId); removeFromMediaStore(visibleFile); } diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index 37f68233db531d1a9764fd3d7a3c62197b765609..3bcba75ec16328245acb4121702d736580080dc5 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -224,6 +224,8 @@ public final class InputMethodDebug { return "HIDE_DOCKED_STACK_ATTACHED"; case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION: return "HIDE_RECENTS_ANIMATION"; + case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR: + return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index 4b968b45f1224a21e53f07543c9d849fbfad1332..f46626be48a81d090230c97dd0dffb3024aa012e 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -47,7 +47,8 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.HIDE_POWER_BUTTON_GO_HOME, SoftInputShowHideReason.HIDE_DOCKED_STACK_ATTACHED, SoftInputShowHideReason.HIDE_RECENTS_ANIMATION, - SoftInputShowHideReason.HIDE_BUBBLES}) + SoftInputShowHideReason.HIDE_BUBBLES, + SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR}) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ int SHOW_SOFT_INPUT = 0; @@ -147,4 +148,17 @@ public @interface SoftInputShowHideReason { * switching, or collapsing Bubbles. */ int HIDE_BUBBLES = 19; + + /** + * Hide soft input when focusing the same window (e.g. screen turned-off and turn-on) which no + * valid focused editor. + * + * Note: From Android R, the window focus change callback is processed by InputDispatcher, + * some focus behavior changes (e.g. There are an activity with a dialog window, after + * screen turned-off and turned-on, before Android R the window focus sequence would be + * the activity first and then the dialog focused, however, in R the focus sequence would be + * only the dialog focused as it's the latest window with input focus) makes we need to hide + * soft-input when the same window focused again to align with the same behavior prior to R. + */ + int HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR = 20; } diff --git a/core/java/com/android/internal/inputmethod/StartInputFlags.java b/core/java/com/android/internal/inputmethod/StartInputFlags.java index 5a8d2c227256efb1c2f1c0e30f5e6b4723cde693..ac83987ef12c4cf4a16725108e5af78a87cc56d0 100644 --- a/core/java/com/android/internal/inputmethod/StartInputFlags.java +++ b/core/java/com/android/internal/inputmethod/StartInputFlags.java @@ -47,4 +47,10 @@ public @interface StartInputFlags { * documented hence we probably need to revisit this though. */ int INITIAL_CONNECTION = 4; + + /** + * The start input happens when the window gained focus to call + * {@code android.view.inputmethod.InputMethodManager#startInputAsyncOnWindowFocusGain}. + */ + int WINDOW_GAINED_FOCUS = 8; } diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java index ba60fa590792b0ff6c74cbc970db814dd884cca1..b42ea7d0b76944173d3a6be7f005e9ff13e7455d 100644 --- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java +++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java @@ -16,14 +16,8 @@ package com.android.internal.os.logging; -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager.NameNotFoundException; -import android.util.Pair; import android.view.WindowManager.LayoutParams; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.FrameworkStatsLog; /** @@ -32,81 +26,6 @@ import com.android.internal.util.FrameworkStatsLog; */ public class MetricsLoggerWrapper { - private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0; - private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1; - - public static void logPictureInPictureDismissByTap(Context context, - Pair topActivityInfo) { - MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED, - METRIC_VALUE_DISMISSED_BY_TAP); - FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, - getUid(context, topActivityInfo.first, topActivityInfo.second), - topActivityInfo.first.flattenToString(), - FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); - } - - public static void logPictureInPictureDismissByDrag(Context context, - Pair topActivityInfo) { - MetricsLogger.action(context, - MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED, - METRIC_VALUE_DISMISSED_BY_DRAG); - FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, - getUid(context, topActivityInfo.first, topActivityInfo.second), - topActivityInfo.first.flattenToString(), - FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED); - } - - public static void logPictureInPictureMinimize(Context context, boolean isMinimized, - Pair topActivityInfo) { - MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED, - isMinimized); - FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, - getUid(context, topActivityInfo.first, topActivityInfo.second), - topActivityInfo.first.flattenToString(), - FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED); - } - - /** - * Get uid from component name and user Id - * @return uid. -1 if not found. - */ - private static int getUid(Context context, ComponentName componentName, int userId) { - int uid = -1; - if (componentName == null) { - return uid; - } - try { - uid = context.getPackageManager().getApplicationInfoAsUser( - componentName.getPackageName(), 0, userId).uid; - } catch (NameNotFoundException e) { - } - return uid; - } - - public static void logPictureInPictureMenuVisible(Context context, boolean menuStateFull) { - MetricsLogger.visibility(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU, - menuStateFull); - } - - public static void logPictureInPictureEnter(Context context, - int uid, String shortComponentName, boolean supportsEnterPipOnTaskSwitch) { - MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED, - supportsEnterPipOnTaskSwitch); - FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid, - shortComponentName, - FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED); - } - - public static void logPictureInPictureFullScreen(Context context, int uid, - String shortComponentName) { - MetricsLogger.action(context, - MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN); - FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, - uid, - shortComponentName, - FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN); - } - public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) { if (changed) { if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) { diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index b12c5e9ba5b056fb42034301c6f5861e44dfbb08..fbbf7916b31efb8850943bc1f2d21af21d0f71d6 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1094,13 +1094,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mLastWindowFlags = attrs.flags; if (insets != null) { - final Insets systemBarInsets = insets.getInsets(WindowInsets.Type.systemBars()); final Insets stableBarInsets = insets.getInsetsIgnoringVisibility( WindowInsets.Type.systemBars()); - mLastTopInset = systemBarInsets.top; - mLastBottomInset = systemBarInsets.bottom; - mLastRightInset = systemBarInsets.right; - mLastLeftInset = systemBarInsets.left; + final Insets systemInsets = Insets.min( + insets.getInsets(WindowInsets.Type.systemBars() + | WindowInsets.Type.displayCutout()), stableBarInsets); + mLastTopInset = systemInsets.top; + mLastBottomInset = systemInsets.bottom; + mLastRightInset = systemInsets.right; + mLastLeftInset = systemInsets.left; // Don't animate if the presence of stable insets has changed, because that // indicates that the window was either just added and received them for the diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java index 9bf05135c4c5ccb7e859b5416402cc4855310742..a23fc4b57b4570f0702e790bd423ab66563cfb0b 100644 --- a/core/java/com/android/internal/util/ScreenshotHelper.java +++ b/core/java/com/android/internal/util/ScreenshotHelper.java @@ -291,7 +291,7 @@ public class ScreenshotHelper { }; Message msg = Message.obtain(null, screenshotType, screenshotRequest); - final ServiceConnection myConn = mScreenshotConnection; + Handler h = new Handler(handler.getLooper()) { @Override public void handleMessage(Message msg) { @@ -304,8 +304,8 @@ public class ScreenshotHelper { break; case SCREENSHOT_MSG_PROCESS_COMPLETE: synchronized (mScreenshotLock) { - if (myConn != null && mScreenshotConnection == myConn) { - mContext.unbindService(myConn); + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); mScreenshotConnection = null; mScreenshotService = null; } @@ -368,6 +368,7 @@ public class ScreenshotHelper { } } else { Messenger messenger = new Messenger(mScreenshotService); + try { messenger.send(msg); } catch (RemoteException e) { diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index 2302de2cd05801bd09e62dc5b7b880315759945b..b4e108faee2d75facd89a43dddd84d4768714fda 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -23,6 +23,7 @@ import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.util.Log; import java.io.IOException; import java.io.InputStream; @@ -31,6 +32,7 @@ import java.io.InputStream; * A class to extract Bitmaps from a MessagingStyle message. */ public class LocalImageResolver { + private static final String TAG = LocalImageResolver.class.getSimpleName(); private static final int MAX_SAFE_ICON_SIZE_PX = 480; @@ -60,11 +62,18 @@ public class LocalImageResolver { private static BitmapFactory.Options getBoundsOptionsForImage(Uri uri, Context context) throws IOException { - InputStream input = context.getContentResolver().openInputStream(uri); BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options(); - onlyBoundsOptions.inJustDecodeBounds = true; - BitmapFactory.decodeStream(input, null, onlyBoundsOptions); - input.close(); + try (InputStream input = context.getContentResolver().openInputStream(uri)) { + if (input == null) { + throw new IllegalArgumentException(); + } + onlyBoundsOptions.inJustDecodeBounds = true; + BitmapFactory.decodeStream(input, null, onlyBoundsOptions); + } catch (IllegalArgumentException iae) { + onlyBoundsOptions.outWidth = -1; + onlyBoundsOptions.outHeight = -1; + Log.e(TAG, "error loading image", iae); + } return onlyBoundsOptions; } diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java index 3f708f84750c1ff91f201c94e2cacf8c9feb2489..90eeabb47e9aa6826cdb7a09ecc71d8ed3c968d4 100644 --- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java +++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java @@ -464,11 +464,7 @@ public class ResolverDrawerLayout extends ViewGroup { smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, yvel); mDismissOnScrollerFinished = true; } else { - if (isNestedListChildScrolled()) { - mNestedListChild.smoothScrollToPosition(0); - } else if (isNestedRecyclerChildScrolled()) { - mNestedRecyclerChild.smoothScrollToPosition(0); - } + scrollNestedScrollableChildBackToTop(); smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel); } } @@ -493,6 +489,17 @@ public class ResolverDrawerLayout extends ViewGroup { return handled; } + /** + * Scroll nested scrollable child back to top if it has been scrolled. + */ + public void scrollNestedScrollableChildBackToTop() { + if (isNestedListChildScrolled()) { + mNestedListChild.smoothScrollToPosition(0); + } else if (isNestedRecyclerChildScrolled()) { + mNestedRecyclerChild.smoothScrollToPosition(0); + } + } + private void onSecondaryPointerUp(MotionEvent ev) { final int pointerIndex = ev.getActionIndex(); final int pointerId = ev.getPointerId(pointerIndex); diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 5c045b65be22df8afa78cf4b9b166768565e713e..7a5c38385f323f5faef615e7f236fbabd495fb88 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -20,6 +20,7 @@ #include "android_media_AudioTrack.h" #include +#include #include "core_jni_helpers.h" #include @@ -251,7 +252,7 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we jint audioFormat, jint buffSizeInBytes, jint memoryMode, jintArray jSession, jlong nativeAudioTrack, jboolean offload, jint encapsulationMode, - jobject tunerConfiguration) { + jobject tunerConfiguration, jstring opPackageName) { ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d," " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p", jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes, @@ -337,7 +338,8 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we } // create the native AudioTrack object - lpTrack = new AudioTrack(); + ScopedUtfChars opPackageNameStr(env, opPackageName); + lpTrack = new AudioTrack(opPackageNameStr.c_str()); // read the AudioAttributes values auto paa = JNIAudioAttributeHelper::makeUnique(); @@ -371,23 +373,24 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we status_t status = NO_ERROR; switch (memoryMode) { case MODE_STREAM: - status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) - sampleRateInHertz, - format,// word length, PCM - nativeChannelMask, - offload ? 0 : frameCount, - offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_NONE, - audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user) - 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack - 0,// shared mem - true,// thread can call Java - sessionId,// audio session ID - offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK : AudioTrack::TRANSFER_SYNC, - offload ? &offloadInfo : NULL, - -1, -1, // default uid, pid values - paa.get()); - + status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed + // in paa (last argument) + sampleRateInHertz, + format, // word length, PCM + nativeChannelMask, offload ? 0 : frameCount, + offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD + : AUDIO_OUTPUT_FLAG_NONE, + audioCallback, + &(lpJniStorage->mCallbackData), // callback, callback data (user) + 0, // notificationFrames == 0 since not using EVENT_MORE_DATA + // to feed the AudioTrack + 0, // shared mem + true, // thread can call Java + sessionId, // audio session ID + offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK + : AudioTrack::TRANSFER_SYNC, + offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values + paa.get()); break; case MODE_STATIC: @@ -398,22 +401,22 @@ static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject we goto native_init_failure; } - status = lpTrack->set( - AUDIO_STREAM_DEFAULT,// stream type, but more info conveyed in paa (last argument) - sampleRateInHertz, - format,// word length, PCM - nativeChannelMask, - frameCount, - AUDIO_OUTPUT_FLAG_NONE, - audioCallback, &(lpJniStorage->mCallbackData),//callback, callback data (user)); - 0,// notificationFrames == 0 since not using EVENT_MORE_DATA to feed the AudioTrack - lpJniStorage->mMemBase,// shared mem - true,// thread can call Java - sessionId,// audio session ID - AudioTrack::TRANSFER_SHARED, - NULL, // default offloadInfo - -1, -1, // default uid, pid values - paa.get()); + status = lpTrack->set(AUDIO_STREAM_DEFAULT, // stream type, but more info conveyed + // in paa (last argument) + sampleRateInHertz, + format, // word length, PCM + nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE, + audioCallback, + &(lpJniStorage->mCallbackData), // callback, callback data (user) + 0, // notificationFrames == 0 since not using EVENT_MORE_DATA + // to feed the AudioTrack + lpJniStorage->mMemBase, // shared mem + true, // thread can call Java + sessionId, // audio session ID + AudioTrack::TRANSFER_SHARED, + NULL, // default offloadInfo + -1, -1, // default uid, pid values + paa.get()); break; default: @@ -1428,7 +1431,8 @@ static const JNINativeMethod gMethods[] = { {"native_stop", "()V", (void *)android_media_AudioTrack_stop}, {"native_pause", "()V", (void *)android_media_AudioTrack_pause}, {"native_flush", "()V", (void *)android_media_AudioTrack_flush}, - {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;)I", + {"native_setup", + "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioTrack_setup}, {"native_finalize", "()V", (void *)android_media_AudioTrack_finalize}, {"native_release", "()V", (void *)android_media_AudioTrack_release}, diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 7c32ca653114337f1ec42e9cdbc20ea583154756..6becb07d02a4d3de95ced2e063a37820c33977df 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -346,22 +346,6 @@ void android_os_Process_setProcessFrozen( } } -void android_os_Process_enableFreezer( - JNIEnv *env, jobject clazz, jboolean enable) -{ - bool success = true; - - if (enable) { - success = SetTaskProfiles(0, {"FreezerFrozen"}, true); - } else { - success = SetTaskProfiles(0, {"FreezerThawed"}, true); - } - - if (!success) { - jniThrowException(env, "java/lang/RuntimeException", "Unknown error"); - } -} - jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid) { SchedPolicy sp; @@ -1360,7 +1344,6 @@ static const JNINativeMethod methods[] = { {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal}, {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet}, {"setProcessFrozen", "(IIZ)V", (void*)android_os_Process_setProcessFrozen}, - {"enableFreezer", "(Z)V", (void*)android_os_Process_enableFreezer}, {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory}, {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory}, {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index a80bb401385438cbca561ce5d247145f71702766..171a14bfe301f4f420affe7b4c4082192120b06a 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -433,35 +433,36 @@ message GlobalSettingsProto { // Ordered GPU debug layer list for GLES // i.e. ::...: optional SettingProto debug_layers_gles = 7; - // Game Driver - global preference for all Apps + // Updatable Driver - global preference for all Apps // 0 = Default - // 1 = All Apps use Game Driver - // 2 = All Apps use system graphics driver - optional SettingProto game_driver_all_apps = 8; - // Game Driver - List of Apps selected to use Game Driver + // 1 = All Apps use updatable production driver + // 2 = All apps use updatable prerelease driver + // 3 = All Apps use system graphics driver + optional SettingProto updatable_driver_all_apps = 8; + // Updatable Driver - List of Apps selected to use updatable production driver // i.e. ,,..., - optional SettingProto game_driver_opt_in_apps = 9; - // Game Driver - List of Apps selected not to use Game Driver + optional SettingProto updatable_driver_production_opt_in_apps = 9; + // Updatable Driver - List of Apps selected not to use updatable production driver // i.e. ,,..., - optional SettingProto game_driver_opt_out_apps = 10; - // Game Driver - List of Apps that are forbidden to use Game Driver - optional SettingProto game_driver_denylist = 11; - // Game Driver - List of Apps that are allowed to use Game Driver - optional SettingProto game_driver_allowlist = 12; + optional SettingProto updatable_driver_production_opt_out_apps = 10; + // Updatable Driver - List of Apps that are forbidden to use updatable production driver + optional SettingProto updatable_driver_production_denylist = 11; + // Updatable Driver - List of Apps that are allowed to use updatable production driver + optional SettingProto updatable_driver_production_allowlist = 12; // ANGLE - List of Apps that can check ANGLE rules optional SettingProto angle_allowlist = 13; - // Game Driver - List of denylists, each denylist is a denylist for - // a specific Game Driver version - optional SettingProto game_driver_denylists = 14; + // Updatable Driver - List of denylists, each denylist is a denylist for + // a specific updatable production driver version + optional SettingProto updatable_driver_production_denylists = 14; // ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG optional SettingProto show_angle_in_use_dialog = 15; - // Game Driver - List of libraries in sphal accessible by Game Driver - optional SettingProto game_driver_sphal_libraries = 16; + // Updatable Driver - List of libraries in sphal accessible by updatable driver + optional SettingProto updatable_driver_sphal_libraries = 16; // ANGLE - External package containing ANGLE libraries optional SettingProto angle_debug_package = 17; - // Game Driver - List of Apps selected to use prerelease Game Driver + // Updatable Driver - List of Apps selected to use updatable prerelease driver // i.e. ,,..., - optional SettingProto game_driver_prerelease_opt_in_apps = 18; + optional SettingProto updatable_driver_prerelease_opt_in_apps = 18; } optional Gpu gpu = 59; diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index fe8a0f1835465afe86dc96fba6a68f85868659cc..cfd428cbacc3dfea8c85347ce081a10f6bb69a20 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -119,6 +119,14 @@ message SecureSettingsProto { } optional Assist assist = 7; + message AssistHandles { + option (android.msg_privacy).dest = DEST_EXPLICIT; + + optional SettingProto learning_time_elapsed_millis = 1 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto learning_event_count = 2 [ (android.privacy).dest = DEST_AUTOMATIC ]; + } + optional AssistHandles assist_handles = 86; + message Autofill { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -180,6 +188,7 @@ message SecureSettingsProto { optional SettingProto cmas_additional_broadcast_pkg = 14 [ (android.privacy).dest = DEST_AUTOMATIC ]; repeated SettingProto completed_categories = 15; optional SettingProto connectivity_release_pending_intent_delay_ms = 16 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto adaptive_connectivity_enabled = 84 [ (android.privacy).dest = DEST_AUTOMATIC ]; message Controls { option (android.msg_privacy).dest = DEST_EXPLICIT; @@ -595,5 +604,5 @@ message SecureSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 82; + // Next tag = 87; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e6619f58f273f72288933815b47ef7c5099cd326..7b656c57b8654b90931c4081589515919e07960b 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -144,7 +144,7 @@ - + @@ -1345,7 +1345,7 @@ android:priority="800" /> + + + diff --git a/core/res/res/drawable-car/car_dialog_button_background.xml b/core/res/res/drawable-car/car_dialog_button_background.xml index a7d40bcd759a21e7c46dd2f0b4332ac11bfdbeb1..72e5af308c010115c251af45d676372c2a32ad30 100644 --- a/core/res/res/drawable-car/car_dialog_button_background.xml +++ b/core/res/res/drawable-car/car_dialog_button_background.xml @@ -16,11 +16,18 @@ --> - - - + + + + + - + + + + + + diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml index 3615b9e2f9cb1a213fba9c01dc5d0ffd01667125..df271f0f2942c77b1e7429786bf7868b916be5c0 100644 --- a/core/res/res/layout/notification_material_action_list.xml +++ b/core/res/res/layout/notification_material_action_list.xml @@ -25,6 +25,7 @@ android:id="@+id/actions_container_layout" android:layout_width="match_parent" android:layout_height="wrap_content" + android:gravity="end" android:orientation="horizontal" android:paddingEnd="@dimen/bubble_gone_padding_end" > diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index d8d3831d016abb7f66758688249d39af9db9b64e..7d773d902bbe98eb137880a72308567791f0ca03 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -829,7 +829,7 @@ "Druk kieslys om oop te sluit of maak noodoproep." "Druk kieslys om oop te maak." "Teken patroon om te ontsluit" - "Noodgeval" + "Noodoproep" "Keer terug na oproep" "Reg!" "Probeer weer" diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index b75891b586fe424ceed651cdf09222a26985f3d1..57f2d6aea741ce1a89256bf40cc82e35d544de26 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -829,7 +829,7 @@ "ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።" "ለመክፈት ምናሌ ተጫን" "ለመክፈት ስርዓተ ጥለት ሳል" - "ድንገተኛ አደጋ" + "የአደጋ ጊዜ ጥሪ" "ወደ ጥሪ ተመለስ" "ትክክል!" "እንደገና ሞክር" diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 6187df981e9818d90f31818aafea4c23b80cfdae..4a99ec8021e82859edf602c5c08399f73fe46bb9 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -841,7 +841,7 @@ "اضغط على \"القائمة\" لإلغاء التأمين أو إجراء اتصال بالطوارئ." "اضغط على \"القائمة\" لإلغاء التأمين." "رسم نقش لإلغاء التأمين" - "الطوارئ" + "مكالمة طوارئ" "العودة إلى الاتصال" "صحيح!" "أعد المحاولة" diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 1ecda856e574f73323393bd3209b2ee25c5281c8..4ff2a6a062ec146892881b77e7c7814f1784e505 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -829,7 +829,7 @@ "আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।" "আনলক কৰিবলৈ মেনু টিপক।" "আনলক কৰিবলৈ আর্হি আঁকক" - "জৰুৰীকালীন" + "জৰুৰীকালীন কল" "কললৈ উভতি যাওক" "শুদ্ধ!" "আকৌ চেষ্টা কৰক" diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index cfae36730693d642bbb1be232061a87fcd7729bc..1d5d6d87b2c52117478d7e35fae33d538f6dc402 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -829,7 +829,7 @@ "Təcili zəng kilidini açmaq və ya yerləşdirmək üçün Menyu düyməsinə basın." "Kilidi açmaq üçün Menyu düyməsinə basın." "Kilidi açmaq üçün model çəkin" - "Təcili" + "Təcili zəng" "Zəngə qayıt" "Düzdür!" "Bir də cəhd edin" diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 57e063566dcae0e3779a06c5801894b8fa03e9fd..daec63a9d5a5b16bb7b3933f21d031cf14b2db78 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -832,7 +832,7 @@ "Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv." "Pritisnite „Meni“ za otključavanje." "Unesite šablon za otključavanje" - "Hitne službe" + "Hitan poziv" "Nazad na poziv" "Tačno!" "Probajte ponovo" diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index f10606cd3a53c4586ce1f39d485c4bde16dcff52..6fbdd4626b94a8dd948456392db7830d3d78c8a8 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -835,7 +835,7 @@ "Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік." "Націсніце \"Меню\", каб разблакаваць." "Намалюйце камбінацыю разблакоўкі, каб разблакаваць" - "Экстранны выклік" + "Экстранны выклік" "Вярнуцца да выкліку" "Правільна!" "Паўтарыце спробу" diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index fce56805f927be5c502eb2799c36d7d6548c1729..a7012a0c2745087d81bfcdd11f5975a473b1802f 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -829,7 +829,7 @@ "Натиснете „Меню“, за да отключите или да извършите спешно обаждане." "Натиснете „Меню“, за да отключите." "Нарисувайте фигура, за да отключите" - "Спешни случаи" + "Спешно обаждане" "Назад към обаждането" "Правилно!" "Опитайте отново" diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index a737cedbce4635dd5866bf462632745a591b4686..c1c40991e902822c37aec484d94cc5add2966ae2 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -829,7 +829,7 @@ "আনলক করতে বা জরুরি কল করতে মেনু টিপুন৷" "আনলক করতে মেনু টিপুন৷" "আনলক করতে প্যাটার্ন আঁকুন" - "জরুরী" + "জরুরি কল" "কলে ফিরুন" "সঠিক!" "আবার চেষ্টা করুন" diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index c9867180670537ddea01afb30959658b89009138..5c5f82208499a6bb05e4b2b9bda26d32250eef6d 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -832,7 +832,7 @@ "Pritisnite dugme Meni kako biste otključali uređaj ili obavili hitni poziv." "Pritisnite dugme Meni za otključavanje uređaja." "Nacrtajte uzorak za otključavanje" - "Hitno" + "Hitni poziv" "Povratak na poziv" "Ispravno!" "Pokušajte ponovo" diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 40ce89c9b94d20c5edca69fd24306bf4529b828c..f85fe5ac935999c3ff8829e0ed2d01b8e66c5ac5 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -829,7 +829,7 @@ "Premeu Menú per desbloquejar-lo o per fer una trucada d\'emergència." "Premeu Menú per desbloquejar." "Dibuixeu el patró de desbloqueig" - "Emergència" + "Trucada d\'emergència" "Torna a la trucada" "Correcte!" "Torna-ho a provar" diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index ba9e060359967b304f020e6566bea74eec8b7305..0edeb0bad4bbcdf2ab1033af75e658cb4e313ae3 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -835,7 +835,7 @@ "Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu." "Telefon odemknete stisknutím tlačítka Menu." "Odblokujte pomocí gesta" - "Stav nouze" + "Tísňové volání" "Zavolat zpět" "Správně!" "Zkusit znovu" diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 138285056de12d90f7bc0335615720d37d8f207d..09e2ea20cd923cfc0f02b8f971feeabe148224aa 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -829,7 +829,7 @@ "Tryk på Menu for at låse op eller foretage et nødopkald." "Tryk på Menu for at låse op." "Tegn oplåsningsmønster" - "Nødsituation" + "Nødopkald" "Tilbage til opkald" "Rigtigt!" "Prøv igen" diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 0f00b56bf7eaacf4d7cfde8aa9125066cc696b2a..627a3ab6a4fdf35c8143fadce81ce9907fe40813 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -829,7 +829,7 @@ "Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen." "Zum Entsperren die Menütaste drücken" "Muster zum Entsperren zeichnen" - "Notruf" + "Notruf" "Zurück zum Anruf" "Korrekt!" "Erneut versuchen" diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 4fd5d4c20c004cff50a664efcc27675c316bc8f7..9435d34b562e86bb54e00f110559bab9584d5f10 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -829,7 +829,7 @@ "Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης." "Πατήστε \"Μενού\" για ξεκλείδωμα." "Σχεδιασμός μοτίβου για ξεκλείδωμα" - "Κλήση έκτακτης ανάγκης" + "Κλήση έκτακτης ανάγκης" "Επιστροφή στην κλήση" "Σωστό!" "Προσπαθήστε ξανά" diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1586cf70ec59ba932af1f9f6badbfb144b979941..c748cc80cb23bf494c9f29c0a69068cae3ee7294 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -829,7 +829,7 @@ "Press Menu to unlock or place emergency call." "Press Menu to unlock." "Draw pattern to unlock" - "Emergency" + "Emergency call" "Return to call" "Correct!" "Try again" diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index c8fb137a70464e14061cd9ff23ba17563fe86c8c..d6faf46ee74a71ee69a7ac6a31c1d0dd611cc994 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -829,7 +829,7 @@ "Press Menu to unlock or place emergency call." "Press Menu to unlock." "Draw pattern to unlock" - "Emergency" + "Emergency call" "Return to call" "Correct!" "Try again" diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 76843dbf5ec28503284d3c28a53b9e9044c635b3..695ddb0e4e4eb2c1fc40c9d4257d52550e9a7af6 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -829,7 +829,7 @@ "Press Menu to unlock or place emergency call." "Press Menu to unlock." "Draw pattern to unlock" - "Emergency" + "Emergency call" "Return to call" "Correct!" "Try again" diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 2ef1b192b13b91b855f319c862a690b8c079b060..596d4b658769d6a193831a9f2cb8e50f2f1493ca 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -829,7 +829,7 @@ "Press Menu to unlock or place emergency call." "Press Menu to unlock." "Draw pattern to unlock" - "Emergency" + "Emergency call" "Return to call" "Correct!" "Try again" diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index b71fcb49603cfa4c92be9a40adeea790004ed091..2cd891f5728175755ce094c2daa2b7dfc3448817 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -829,7 +829,7 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‎Press Menu to unlock or place emergency call.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‎‏‎Press Menu to unlock.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎Draw pattern to unlock‎‏‎‎‏‎" - "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎Emergency‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎Emergency call‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎Return to call‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‎Correct!‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‎‎Try again‎‏‎‎‏‎" diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 32d6c24ffae703147e0fc2dd3267c5242945e5a4..4d93d6eaf641c19d014fcfc9dc49d45e312b3fbc 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -829,7 +829,7 @@ "Presiona el Menú para desbloquear o realizar una llamada de emergencia." "Presionar Menú para desbloquear." "Dibujar el patrón de desbloqueo" - "Emergencia" + "Llamada de emergencia" "Regresar a llamada" "Correcto" "Vuelve a intentarlo." diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 3ca71e63d1c325a9fd6b8d985a995d7a3bc762d6..7b6dea33ef60d28221fc76d7027d44ffaa329952 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -829,7 +829,7 @@ "Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia." "Pulsa la tecla de menú para desbloquear la pantalla." "Dibujar patrón de desbloqueo" - "Emergencia" + "Llamada de emergencia" "Volver a llamada" "Correcto" "Vuelve a intentarlo" diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 3b8ae1d2cf7397a2df2e2eb0bce10af6d0772898..ea6fabe0556f1e6f8a2fb9f63ee7540e9b488895 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -829,7 +829,7 @@ "Vajutage avamiseks või hädaabikõne tegemiseks menüünuppu" "Vajutage avamiseks menüüklahvi." "Avamiseks joonistage muster" - "Hädaabi" + "Hädaabikõne" "Kõne juurde tagasi" "Õige." "Proovige uuesti" diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index e79052b0615eb98d2cf155796e15181a9f734e65..5e52506c40db17fa31cac0f4999643c69661f799 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -829,7 +829,7 @@ "Desblokeatzeko edo larrialdi-deia egiteko, sakatu Menua." "Desblokeatzeko, sakatu Menua." "Desblokeatzeko, marraztu eredua" - "Larrialdi-deiak" + "Larrialdi-deia" "Itzuli deira" "Eredua zuzena da!" "Saiatu berriro" diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 656de3525fad06c72f179acc0d9461b6b5f5a655..fe283abb769980764e5fcfc13147d85eaaa97c9c 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -829,7 +829,7 @@ "برای بازکردن قفل یا انجام تماس اضطراری روی «منو» فشار دهید." "برای بازگشایی قفل روی منو فشار دهید." "الگو را بکشید تا قفل آن باز شود" - "اضطراری" + "تماس اضطراری" "بازگشت به تماس" "صحیح است!" "دوباره امتحان کنید" diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4061662a337202bdaeee83cdae1736c959c2b0a7..527d5a6a80874171ba47d43f90ab97fc51b587cd 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -829,7 +829,7 @@ "Poista lukitus tai soita hätäpuhelu painamalla Valikko-painiketta." "Poista lukitus painamalla Valikko-painiketta." "Poista lukitus piirtämällä kuvio" - "Hätäpuhelu" + "Hätäpuhelu" "Palaa puheluun" "Oikein!" "Yritä uudelleen" diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 9035291a2e3ccb2aff53699b3650e4a87fd3d689..e8d64088667d98b0d6fefba1853dbc32f9ab2ede 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -832,7 +832,7 @@ "Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence." "Appuyez sur \"Menu\" pour déverrouiller l\'appareil." "Dessinez un schéma pour déverrouiller le téléphone" - "Urgence" + "Appel d\'urgence" "Retour à l\'appel" "C\'est exact!" "Réessayer" diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 8b1b85dba338c48db0b038809ea75edb015347dc..fc91c47b700bb746cd7b8ca4900fd2ca9be5a798 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -832,7 +832,7 @@ "Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence" "Appuyez sur \"Menu\" pour déverrouiller le téléphone." "Dessinez un schéma pour déverrouiller le téléphone" - "Urgences" + "Appel d\'urgence" "Retour à l\'appel" "Combinaison correcte !" "Veuillez réessayer." diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index b0fe9493073ba028d049fe2ec72a69a28c40090c..7cc6f6934901902412d0540ca63cb03c25cd8c87 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -829,7 +829,7 @@ "Preme Menú para desbloquear ou realizar unha chamada de emerxencia." "Preme Menú para desbloquear." "Crea o padrón de desbloqueo" - "Emerxencia" + "Chamada de emerxencia" "Volver á chamada" "Correcto!" "Téntao de novo" diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 83f50404b94275bdd6d86db2faa1d08a00d5d0fc..55e462c825720d9fcd819c9a60ba170052ee6864 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -829,7 +829,7 @@ "અનલૉક કરવા માટે અથવા કટોકટીનો કૉલ કરવા માટે મેનૂ દબાવો." "અનલૉક કરવા માટે મેનૂ દબાવો." "અનલૉક કરવા માટે પૅટર્ન દોરો." - "ઇમર્જન્સી" + "ઇમર્જન્સી કૉલ" "કૉલ પર પાછા ફરો" "સાચું!" "ફરી પ્રયાસ કરો" diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 63c3a4c879a51454eda2c2a3d03c6e2b12fef780..7d48ce034dbfe4f59716c55f976cf71937fb4c6f 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -829,7 +829,7 @@ "लॉक खोलने के लिए मेन्यू दबाएं या आपातलकालीन कॉल करें." "लॉक खोलने के लिए मेन्यू दबाएं." "अनलॉक करने के लिए आकार आरेखित करें" - "आपातकाल" + "आपातकालीन कॉल" "कॉल पर वापस लौटें" "सही!" "फिर से कोशिश करें" diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 4a4b6a73bca0cfc46abc7be5428b0b7ab2b3dd70..d0ad16e93f9a9de86607ecce025e61c1b64a12fa 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -832,7 +832,7 @@ "Pritisnite Izbornik za otključavanje ili pozivanje hitnih službi." "Pritisnite Izbornik za otključavanje." "Iscrtajte uzorak za otključavanje" - "Hitne službe" + "Hitni poziv" "Uzvrati poziv" "Ispravno!" "Pokušajte ponovo" diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 711b413ff73b65d647c56ab1186b40751679d4d4..34e1db5ef4ce0e128134f809c8dbfaf59c1403ec 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -829,7 +829,7 @@ "A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot." "A feloldáshoz nyomja meg a Menü gombot." "Rajzolja le a mintát a feloldáshoz" - "Segélyhívás" + "Segélyhívás" "Hívás folytatása" "Helyes!" "Próbálja újra" diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index c88af9943a69a7befb34694a32cbd687687a1b79..da83ae5ef6f384711450047c697f05368a381352 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -829,7 +829,7 @@ "Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»" "Ապակողպելու համար սեղմեք Ցանկը:" "Հավաքեք սխեման` ապակողպելու համար" - "Շտապ կանչ" + "Շտապ կանչ" "Վերադառնալ զանգին" "Ճիշտ է:" "Կրկին փորձեք" diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 4aed7224aab366271cfd568e0e6a004ef5b5a45b..b72ffe219a05b67d4ecc870df91d9f045638e07d 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -829,7 +829,7 @@ "Tekan Menu untuk membuka atau melakukan panggilan darurat." "Tekan Menu untuk membuka." "Buat pola untuk membuka" - "Darurat" + "Panggilan darurat" "Kembali ke panggilan" "Perbaiki!" "Coba lagi" diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index a6094c57ca7ecdd4dd9e3fe5ec8b357f80ce6002..1ca4e619b66c02b17764025e66d38d3d198b07cb 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -829,7 +829,7 @@ "Ýttu á valmyndartakkann til að taka úr lás eða hringja neyðarsímtal." "Ýttu á valmyndartakkann til að taka úr lás." "Teiknaðu mynstur til að taka úr lás" - "Neyðarsímtal" + "Neyðarsímtal" "Aftur í símtal" "Rétt!" "Reyndu aftur" diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 1d8b3f264669ef3e4d7871d94606f7dc2eb43dda..95e1a48e1c68fe9d0854c3f73dc6e7b5cff1106d 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -829,7 +829,7 @@ "Premi Menu per sbloccare o effettuare chiamate di emergenza." "Premi Menu per sbloccare." "Traccia la sequenza di sblocco" - "Emergenza" + "Chiamata di emergenza" "Torna a chiamata" "Corretta." "Riprova" diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 3ec4e7432510e3edfca79aa1b48447d118f9d61a..138975337b558b3e28694456bf6865af46ea24d9 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -835,7 +835,7 @@ "לחץ על \'תפריט\' כדי לבטל את הנעילה או כדי לבצע שיחת חירום." "לחץ על \'תפריט\' כדי לבטל את הנעילה." "שרטט קו לביטול נעילת המסך" - "חירום" + "שיחת חירום" "חזרה לשיחה" "נכון!" "כדאי לנסות שוב" diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 29ac44ddaa50206bad08e0f6f939b615cb2c2b3d..44c901cebacc324cc509a7609eddca26719b81e4 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -829,7 +829,7 @@ "MENUキーでロック解除(または緊急通報)" "MENUキーでロック解除" "パターンを入力" - "緊急通報" + "緊急通報" "通話に戻る" "一致しました" "もう一度お試しください" diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 96debbac1dbabbfec7dcc940475c5f2193188a36..7365b05ee513c971d089cef7ff302620e569d818 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -829,7 +829,7 @@ "განბლოკვისთვის ან გადაუდებელი ზარისთვის დააჭირეთ მენიუს." "განბლოკვისთვის დააჭირეთ მენიუს." "განსაბლოკად დახატეთ ნიმუში" - "საგანგებო სამსახურები" + "გადაუდებელი ზარი" "ზარზე დაბრუნება" "სწორია!" "კიდევ სცადეთ" diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 8b06cd4d1f2ade8f28cd50b7e3427f39ce194722..04020fb643a8a62e5f576e9b1a7b7b6030cbd444 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -829,7 +829,7 @@ "Бекітпесін ашу үшін немесе төтенше қоңырауды табу үшін Мәзір тармағын басыңыз." "Ашу үшін Мәзір пернесін басыңыз." "Бекітпесін ашу үшін кескінді сызыңыз" - "Төтенше жағдай" + "Құтқару қызметіне қоңырау шалу" "Қоңырауға оралу" "Дұрыс!" "Қайталап көріңіз" diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 2980a5bf95209e97a3cc156f7085bbccacd53541..43f0a1ce43bce45252917b5e6f995f997d771543 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -829,7 +829,7 @@ "ចុច​ម៉ឺនុយ ដើម្បី​ដោះ​សោ​ ឬ​ហៅ​ពេល​អាសន្ន។" "ចុច​ម៉ឺនុយ ដើម្បី​ដោះ​សោ។" "គូរ​លំនាំ ដើម្បី​ដោះ​សោ" - "បន្ទាន់" + "ហៅទៅលេខសង្គ្រោះបន្ទាន់" "ត្រឡប់​ទៅ​ការ​ហៅ" "ត្រឹមត្រូវ!" "ព្យាយាម​ម្ដង​ទៀត" diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 484276b708f42c6b721131cd910e10f8f7b34f6b..9b226889bd4fca2f50a56cd52375c09e86bad3d8 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -829,7 +829,7 @@ "ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ ಇಲ್ಲವೇ ತುರ್ತು ಕರೆಯನ್ನು ಮಾಡಿ." "ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ." "ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ" - "ತುರ್ತು" + "ತುರ್ತು ಕರೆ" "ಕರೆಗೆ ಹಿಂತಿರುಗು" "ಸರಿಯಾಗಿದೆ!" "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ" diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 5551835e4753ac92ca3fd4f671204284b552ff9d..636de4e19f7c8d3366ce9dc87d43fc12be867e6f 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -829,7 +829,7 @@ "비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요." "잠금해제하려면 메뉴를 누르세요." "잠금해제를 위해 패턴 그리기" - "긴급 전화" + "긴급 전화" "통화로 돌아가기" "맞습니다." "다시 시도" diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 69efba6f16cb3b711b11d88b490c3a32a5fbaae1..d9ea68602cf42baac57788d05f5ce1d4ff5b92df 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -829,7 +829,7 @@ "Кулпусун ачып же Шашылыш чалуу аткаруу үчүн менюну басыңыз." "Бөгөттөн чыгаруу үчүн Менюну басыңыз." "Кулпуну ачуу үчүн, үлгүнү тартыңыз" - "Шашылыш чалуу" + "Шашылыш чалуу" "Чалууга кайтуу" "Туура!" "Дагы аракет кылыңыз" diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 242d819515ec6123f71e870bb3672634189dc9a5..2197aee867f3026e54115f1bf97f9ecdff467f17 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -829,7 +829,7 @@ "ກົດ ເມນູ ເພື່ອປົດລັອກ ຫຼື ໂທອອກຫາເບີສຸກເສີນ." "ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ." "ແຕ້ມຮູບແບບເພື່ອປົດລັອກ" - "ສຸກ​ເສີນ" + "ການໂທສຸກເສີນ" "ກັບໄປຫາການໂທ" "ຖືກຕ້ອງ!" "ລອງໃໝ່ອີກຄັ້ງ" diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index f03439004c5650f198cd0194df1c70810f30c994..6a49582197328242b5481a57aed5d0c315dbfbec 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -835,7 +835,7 @@ "Paspauskite „Meniu“, kad atrakintumėte ar skambintumėte pagalbos numeriu." "Paspauskite „Meniu“, jei norite atrakinti." "Nustatyti modelį, kad atrakintų" - "Skambutis pagalbos numeriu" + "Skambutis pagalbos numeriu" "grįžti prie skambučio" "Teisingai!" "Bandykite dar kartą" diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 65f741f4d3325804c5d8a14d6e5d7ab2a0c7941d..8e67568e1718baf5be49fa1cb4bd8c75159fe33a 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -832,7 +832,7 @@ "Nospiediet Izvēlne, lai atbloķētu, vai veiciet ārkārtas zvanu." "Lai atbloķētu, nospiediet vienumu Izvēlne." "Zīmējiet kombināciju, lai atbloķētu." - "Ārkārtas situācija" + "Ārkārtas izsaukums" "Atpakaļ pie zvana" "Pareizi!" "Mēģināt vēlreiz" diff --git a/core/res/res/values-mcc260/config.xml b/core/res/res/values-mcc260/config.xml new file mode 100644 index 0000000000000000000000000000000000000000..79eefb7cecbe6fcffed858326ca5378c818e1461 --- /dev/null +++ b/core/res/res/values-mcc260/config.xml @@ -0,0 +1,25 @@ + + + + + + + false + \ No newline at end of file diff --git a/core/res/res/values-mcc262/config.xml b/core/res/res/values-mcc262/config.xml new file mode 100644 index 0000000000000000000000000000000000000000..79eefb7cecbe6fcffed858326ca5378c818e1461 --- /dev/null +++ b/core/res/res/values-mcc262/config.xml @@ -0,0 +1,25 @@ + + + + + + + false + \ No newline at end of file diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 287ce503a36a1b30f054e47e6edf1a86081999b1..d61a278029b3401245dcacbd9c0ce094cdb6dfdb 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -829,7 +829,7 @@ "Притисни „Мени“ да се отклучи или да направи итен повик." "Притиснете „Мени“ за да се отклучи." "Употребете ја шемата за да се отклучи" - "Итен случај" + "Итен повик" "Врати се на повик" "Точно!" "Обидете се повторно" diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 4a99d809eefbd6ec2fdf5ab73f1b8455eb092588..d30861f22b751b75abc15bccfed141273ba7b3da 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -829,7 +829,7 @@ "അൺലോക്ക് ചെയ്യുന്നതിനായി മെനു അമർത്തുക അല്ലെങ്കിൽ അടിയന്തര കോൾ വിളിക്കുക." "അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക." "അൺലോക്ക് ചെയ്യാൻ പാറ്റേൺ വരയ്‌ക്കുക" - "എമർജൻസി" + "എമർജൻസി കോൾ" "കോളിലേക്ക് മടങ്ങുക" "ശരി!" "വീണ്ടും ശ്രമിക്കുക" diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 35eccd1c5d147545dc600ff030df068742ff1d08..657f680fb8d924dc927695615a437dd73b305faa 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -829,7 +829,7 @@ "Яаралтай дуудлага хийх буюу эсвэл түгжээг тайлах бол цэсийг дарна уу." "Тайлах бол цэсийг дарна уу." "Тайлах хээгээ зурна уу" - "Яаралтай тусламж" + "Яаралтай дуудлага" "Дуудлагаруу буцах" "Зөв!" "Дахин оролдох" diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 521861d3351e2a734c2bb8aaedecd0aeba7af338..a1c4b63b804b7b0a4d49d16c77daf09ef581eb5f 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -829,7 +829,7 @@ "अनलॉक करण्‍यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा." "अनलॉक करण्यासाठी मेनू दाबा." "अनलॉक करण्यासाठी पॅटर्न काढा" - "आणीबाणी" + "आणीबाणी कॉल" "कॉलवर परत या" "अचूक!" "पुन्हा प्रयत्न करा" diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index d578090289f3966555dae1b90c5cf325a1e06350..f715dc60459fe627d9e9a1540cacac9edcd3f411 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -829,7 +829,7 @@ "Tekan Menu untuk menyahsekat atau membuat panggilan kecemasan." "Tekan Menu untuk membuka kunci." "Lukiskan corak untuk membuka kunci" - "Kecemasan" + "Panggilan kecemasan" "Kembali ke panggilan" "Betul!" "Cuba lagi" diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index e911623592052d935bef1bb7c0e57c9fbdf1aee7..9ba7fef6377315f2ca72a9e751bdceb176ca8bfd 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -829,7 +829,7 @@ "ဖွင့်ရန်သို့မဟုတ်အရေးပေါ်ခေါ်ဆိုခြင်းပြုလုပ်ရန် မီနူးကိုနှိပ်ပါ" "မီးနူးကို နှိပ်ခြင်းဖြင့် သော့ဖွင့်ပါ" "ဖွင့်ရန်ပုံစံဆွဲပါ" - "အရေးပေါ်" + "အရေးပေါ် ခေါ်ဆိုမှု" "ခေါ်ဆိုမှုထံပြန်သွားရန်" "မှန်ပါသည်" "ထပ် စမ်းပါ" diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 5e7e66f53174d9871913f0044043196b7ffa5ac7..4a89f37af14767b25db17037c68bc65de9be78ab 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -829,7 +829,7 @@ "Trykk på menyknappen for å låse opp eller ringe et nødnummer." "Trykk på menyknappen for å låse opp." "Tegn mønster for å låse opp" - "Nødssituasjon" + "Nødanrop" "Tilbake til samtale" "Riktig!" "Prøv på nytt" diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index ce2cf69cc938cf19ecece6db1d2c08adf64977d5..6723e66940494fb9bb5118a7ce7465712e01adcc 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -829,7 +829,7 @@ "अनलक वा आपत्‌कालीन कल गर्न मेनु थिच्नुहोस्।" "अनलक गर्न मेनु थिच्नुहोस्।" "अनलक गर्नु ढाँचा खिच्नुहोस्" - "आपत्‌कालीन" + "आपत्‌कालीन कल" "कलमा फर्किनुहोस्" "सही!" "फेरि प्रयास गर्नुहोस्" diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 9c4acb17d5530ea8d280431d238e393ff39f2b23..bae44fd801ba480020f19dcc69427d209b72cf47 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -829,7 +829,7 @@ "Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen." "Druk op \'Menu\' om te ontgrendelen." "Patroon tekenen om te ontgrendelen" - "Noodgeval" + "Noodoproep" "Terug naar gesprek" "Juist!" "Opnieuw proberen" diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 4baab0eb34ee9ba765e42efe763d02bc42066611..72fbc1d317815f640a370b8993227e24322a39db 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -829,7 +829,7 @@ "ଅନଲକ୍‌ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ କିମ୍ବା ଜରୁରୀକାଳୀନ କଲ୍‌ କରନ୍ତୁ।" "ଅନଲକ୍‌ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।" "ଅନଲକ୍‌ କରିବା ପାଇଁ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ" - "ଜରୁରୀକାଳୀନ" + "ଜରୁରୀକାଳୀନ କଲ୍" "କଲ୍‌କୁ ଫେରନ୍ତୁ" "ଠିକ୍!" "ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ" diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index cab0a64a1aa8d8fde9f111d175040a19d9fc560d..45d32f2aa0e43eabeaf7594b69750c64366f3112 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -829,7 +829,7 @@ "ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।" "ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।" "ਅਣਲਾਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ" - "ਸੰਕਟਕਾਲ" + "ਸੰਕਟਕਾਲੀਨ ਕਾਲ" "ਕਾਲ ਤੇ ਵਾਪਸ ਜਾਓ" "ਸਹੀ!" "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ" diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 7feead5d69735a955af938e876292d2ea8393fe8..ef599a16329c5b2d8534c2d9aff764dcb63c6f34 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -835,7 +835,7 @@ "Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe." "Naciśnij Menu, aby odblokować." "Narysuj wzór, aby odblokować" - "Alarmowe" + "Połączenie alarmowe" "Powrót do połączenia" "Poprawnie!" "Spróbuj ponownie." diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index ebe3f412f0313a3e98da3faec08cec4a98b6af01..fa5be924bf85a583cae2fe339a7374ec962732ea 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -829,7 +829,7 @@ "Pressione Menu para desbloquear ou fazer uma chamada de emergência." "Pressione Menu para desbloquear." "Desenhe o padrão para desbloquear" - "Emergência" + "Chamada de emergência" "Retornar à chamada" "Correto!" "Tente novamente" diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index f4fa1d06ae4dbb984ff8f9d3946ca3a38e79e445..1beb966c44215cac55c4c41b85d8472f6cfa4205 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -829,7 +829,7 @@ "Prima Menu para desbloquear ou efectuar uma chamada de emergência." "Prima Menu para desbloquear." "Desenhar padrão para desbloquear" - "Emergência" + "Chamada de emergência" "Regressar à chamada" "Correcto!" "Tentar novamente" diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index ebe3f412f0313a3e98da3faec08cec4a98b6af01..fa5be924bf85a583cae2fe339a7374ec962732ea 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -829,7 +829,7 @@ "Pressione Menu para desbloquear ou fazer uma chamada de emergência." "Pressione Menu para desbloquear." "Desenhe o padrão para desbloquear" - "Emergência" + "Chamada de emergência" "Retornar à chamada" "Correto!" "Tente novamente" diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 4a3bd438e1e0d68ec5d40f0c23b090f97ec14744..bffa4570ef2a250e89320bef2ea861a2ccfc8283 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -832,7 +832,7 @@ "Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență." "Apăsați Meniu pentru deblocare." "Desenați modelul pentru a debloca" - "Urgență" + "Apel de urgență" "Reveniți la apel" "Corect!" "Încercați din nou" diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index d106e79d4ab89945d60de41e22bab6ef11a43aa2..f7f80f2b73c90b53319cafebb653c6905f6e55a2 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -835,7 +835,7 @@ "Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи." "Для разблокировки нажмите \"Меню\"." "Введите графический ключ" - "Экстренный вызов" + "Экстренный вызов" "Вернуться к вызову" "Правильно!" "Повторите попытку" diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 760a41305e43819cab43ccf5299fa295fb4b9510..dc8f723af411d69523bf54c4b872ff53868eed0a 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -829,7 +829,7 @@ "අගුළු හැරීමට මෙනුව ඔබන්න හෝ හදිසි ඇමතුම ලබාගන්න." "අගුළු හැරීමට මෙනු ඔබන්න." "අගුළු ඇරීමට රටාව අඳින්න" - "හදිසි" + "හදිසි ඇමතුම" "ඇමතුම වෙත නැවත යන්න" "නිවැරදියි!" "නැවත උත්සාහ කරන්න" diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 68d40a5a7278790cbc2493f9d735aca9ecd1fb9d..df5cdacfca2a743c51a0dd8f88e08bcbcbfa1eae 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -835,7 +835,7 @@ "Ak chcete odomknúť telefón alebo uskutočniť tiesňové volanie, stlačte Menu." "Telefón odomknete stlačením tlačidla Menu." "Odomknite nakreslením vzoru" - "Stav tiesne" + "Tiesňové volanie" "Zavolať späť" "Správne!" "Skúsiť znova" diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 452a0a4c54ac0597db8c1cd98f2bb116ba70cfad..32cfb18501d2534b26b6be8c995e6f1f661f3e5d 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -835,7 +835,7 @@ "Če želite odkleniti napravo ali opraviti klic v sili, pritisnite meni." "Če želite odkleniti, pritisnite meni." "Če želite odkleniti, narišite vzorec" - "Klic v sili" + "Klic v sili" "Nazaj na klic" "Pravilno." "Poskusi znova" diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 000ec504cfeea3b393b19e88e4c64ea7ea1bfa82..d84b019c97b767603bc93d61e6114f7c61de6de2 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -829,7 +829,7 @@ "Shtyp \"Meny\" për të shkyçur ose për të kryer telefonatë urgjence." "Shtyp \"Meny\" për të shkyçur." "Vizato modelin për ta shkyçur" - "Urgjenca" + "Telefonata e urgjencës" "Kthehu te telefonata" "Saktë!" "Provo sërish" diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 2596ac12add0ec0af68bce379252dfa3eb871c45..d2e78651ef22eb3cc29c51dd844c94e5731f06e9 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -832,7 +832,7 @@ "Притисните „Мени“ да бисте откључали телефон или упутите хитан позив." "Притисните „Мени“ за откључавање." "Унесите шаблон за откључавање" - "Хитне службе" + "Хитан позив" "Назад на позив" "Тачно!" "Пробајте поново" diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index c1e6ac102067a6d9d43fe55998e7a01ca3edec42..279c619c65fca05a9927ff773f2384789d4fc605 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -829,7 +829,7 @@ "Tryck på Menu för att låsa upp eller ringa nödsamtal." "Tryck på Menu för att låsa upp." "Rita grafiskt lösenord för att låsa upp" - "Nödsamtal" + "Nödsamtal" "Tillbaka till samtal" "Korrekt!" "Försök igen" diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 67d53be82a7818aa8607e8f0cd28b1e41ead2504..7066c0054ebff0aeecf996741c4ef5f10579fbbd 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -829,7 +829,7 @@ "Bonyeza Menyu ili kufungua au kupiga simu ya dharura." "Bonyeza Menyu ili kufungua." "Chora ruwaza ili kufungua" - "Dharura" + "Simu ya dharura" "Rudi kwa kupiga simu" "Sahihi!" "Jaribu tena" diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 1284720b80f7b003370cea61ce32a6d0db02eccf..c39e1aa976f90ee7f22e2274ee669271dee0b74b 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -829,7 +829,7 @@ "தடைநீக்க மெனுவை அழுத்தவும் அல்லது அவசர அழைப்பை மேற்கொள்ளவும்." "திறக்க, மெனுவை அழுத்தவும்." "திறக்க வடிவத்தை வரையவும்" - "அவசர அழைப்பு" + "அவசர அழைப்பு" "அழைப்பிற்குத் திரும்பு" "சரி!" "மீண்டும் முயற்சிக்கவும்" diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 1676f1f4c736e29025288aa3849ab985a01f8474..726fd6c6180a5ce8ceecd95e7acc9c639ede4212 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -829,7 +829,7 @@ "అన్‌లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెనూ నొక్కండి." "అన్‌లాక్ చేయడానికి మెనూ నొక్కండి." "అన్‌లాక్ చేయడానికి నమూనాను గీయండి" - "అత్యవసరం" + "ఎమర్జెన్సీ కాల్" "కాల్‌కు తిరిగి వెళ్లు" "సరైనది!" "మళ్లీ ప్రయత్నించండి" diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index bd5a6b60aba1f753797e8e91dbdff91b86c03325..92dd924bd3bb2330100727617d495fd2b9499788 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -829,7 +829,7 @@ "กด เมนู เพื่อปลดล็อกหรือโทรฉุกเฉิน" "กด เมนู เพื่อปลดล็อก" "วาดรูปแบบเพื่อปลดล็อก" - "เหตุฉุกเฉิน" + "หมายเลขฉุกเฉิน" "กลับสู่การโทร" "ถูกต้อง!" "ลองอีกครั้ง" diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 6e5c31078ffe66190f62e9dbd01c3b98a477a4cf..f68ed31dabe1689f069692859a894d079dcb69e4 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -829,7 +829,7 @@ "Pindutin ang Menu upang i-unlock o magsagawa ng pang-emergency na tawag." "Pindutin ang Menu upang i-unlock." "Iguhit ang pattern upang i-unlock" - "Emergency" + "Emergency na tawag" "Bumalik sa tawag" "Tama!" "Subukang muli" diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 145c6bbdbc55a0a6f75891bc8c4e088aed8ddc68..c0266d6b33977a657ff5c3f03fb02af85cdad691 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -829,7 +829,7 @@ "Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın." "Kilidi açmak için Menü\'ye basın." "Kilit açmak için deseni çizin" - "Acil durum çağrısı" + "Acil durum araması" "Çağrıya dön" "Doğru!" "Tekrar deneyin" diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 617509edd9487d0c5f09bb20c7094ce72131270b..d69ac5499a3d8fc38c5520fb054e6242cc62d268 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -835,7 +835,7 @@ "Натис. меню, щоб розбл. чи зробити авар. виклик." "Натисн. меню, щоб розбл." "Намал. ключ, щоб розбл." - "Екстрений виклик" + "Екстрений виклик" "Поверн. до дзвін." "Правильно!" "Повторіть спробу" diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index b845f7e74bd2b9336a0e8eecc1a15c2ed586a944..cdc132e11925e4626f6a38ffb1eb94e950e7c076 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -829,7 +829,7 @@ "غیر مقفل کرنے کیلئے مینو دبائیں یا ہنگامی کال کریں۔" "غیر مقفل کرنے کیلئے مینو دبائیں۔" "غیر مقفل کرنے کیلئے پیٹرن کو ڈرا کریں" - "ہنگامی" + "ہنگامی کال" "کال پر واپس جائیں" "صحیح!" "دوبارہ کوشش کریں" diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 1a3ecd0b46179daabaf82eaa69f64e8a1fff0d14..e8449c31639e40d2419ddd839f0899f8db501926 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -829,7 +829,7 @@ "Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing." "Qulfni ochish uchun \"Menyu\"ga bosing." "Qulfni ochish uchun grafik kalitni chizing" - "Favqulodda chaqiruv" + "Favqulodda chaqiruv" "Qo‘ng‘iroqni qaytarish" "To‘g‘ri!" "Qaytadan urining" diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index c2caedda82ed02ea905cad6b85c6b06340989b60..bf7fbca64581090f2025a66600299ac1b7fd962c 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -829,7 +829,7 @@ "Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp." "Nhấn vào Menu để mở khóa." "Vẽ hình để mở khóa" - "Khẩn cấp" + "Cuộc gọi khẩn cấp" "Quay lại cuộc gọi" "Chính xác!" "Thử lại" diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 2766440b8674f2749d6cf06f252dd3bf4a3ffea2..a645cd7db90aeff1e7cee288b7ddca185163bba0 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -829,7 +829,7 @@ "按 Menu 解锁或进行紧急呼救。" "按 MENU 解锁。" "绘制解锁图案" - "紧急呼救" + "紧急呼叫" "返回通话" "正确!" "重试" diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index b1b21acce1d4e29c8cbb277e02e993918d290e23..cb61121b64e0889854cd22711f18fcffbcbc9793 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -829,7 +829,7 @@ "按選單鍵解鎖或撥打緊急電話。" "按選單鍵解鎖。" "畫出解鎖圖形以解除鎖定螢幕" - "緊急電話" + "緊急電話" "返回通話" "正確!" "再試一次" diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index a65d6fdf10e76ac097cfde005baa5b196408bc32..4d2d86ad9856f9dfa02f8f0bf211c73169d1e395 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -829,7 +829,7 @@ "按下 [Menu] 解鎖或撥打緊急電話。" "按下 Menu 鍵解鎖。" "畫出解鎖圖案" - "緊急撥號" + "緊急電話" "返回通話" "正確!" "再試一次" diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 883bed29ad159b836960a36fe775deb04cd407cf..bb5360edb0b855ead44614b6ae01b4a291ebf3d3 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -829,7 +829,7 @@ "Chofoza Menyu ukuvula noma ukwenza ikholi ephuthumayo." "Chofoza Menyu ukuvula." "Dweba iphathini ukuvula" - "Isimo esiphuthumayo" + "Ikholi ephuthumayo" "Buyela ekholini" "Lungile!" "Zama futhi" diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 8a4676dec6b3535db918642cafce2b1f58e908f7..2f1bcdc76afbb3aac220289f0aaf28003578278c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1259,7 +1259,12 @@ + {@link android.text.InputType#TYPE_TEXT_FLAG_MULTI_LINE}. + + Note: If this flag is not set and the text field doesn't have max length limit, the + framework automatically set maximum length of the characters to 5000 for the + performance reasons. + --> true - - false + + false @@ -2275,7 +2282,7 @@ - 500 + 0 @@ -2305,7 +2312,7 @@ - false + true true diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml index 3a1679c19fc8805c673930ed37327f39c019fa23..f46f70c2debf8088d6602bf03ac7ca343df5b2e3 100644 --- a/core/res/res/values/donottranslate.xml +++ b/core/res/res/values/donottranslate.xml @@ -23,7 +23,7 @@ square - eeeMMMMd + EEEMMMMd @string/icu_abbrev_wday_month_day_no_year + + Draw pattern to unlock - Emergency + Emergency call Return to call diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 36e94e5ed1ab4a32eff9e943dace00e4ff92b485..c505afe0509e32e2d0c6af431d4271810cdd050a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1671,7 +1671,7 @@ - + diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index b39c89b62eb16f90a64cceaa4967d5b307031b32..6aa5dfc5a11ef02b6386280f51861bba3618608d 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -129,6 +129,7 @@ + diff --git a/core/tests/coretests/res/values/overlayable_icons_test.xml b/core/tests/coretests/res/values/overlayable_icons_test.xml new file mode 100644 index 0000000000000000000000000000000000000000..7ea1848a723e27de21b9afcab26fd79f2c708f8c --- /dev/null +++ b/core/tests/coretests/res/values/overlayable_icons_test.xml @@ -0,0 +1,86 @@ + + + + + @*android:drawable/ic_audio_alarm + @*android:drawable/ic_audio_alarm_mute + @*android:drawable/ic_battery_80_24dp + @*android:drawable/ic_bluetooth_share_icon + @*android:drawable/ic_bt_headphones_a2dp + @*android:drawable/ic_bt_headset_hfp + @*android:drawable/ic_bt_hearing_aid + @*android:drawable/ic_bt_laptop + @*android:drawable/ic_bt_misc_hid + @*android:drawable/ic_bt_network_pan + @*android:drawable/ic_bt_pointing_hid + @*android:drawable/ic_corp_badge + @*android:drawable/ic_expand_more + @*android:drawable/ic_faster_emergency + @*android:drawable/ic_file_copy + @*android:drawable/ic_lock + @*android:drawable/ic_lock_bugreport + @*android:drawable/ic_lock_open + @*android:drawable/ic_lock_power_off + @*android:drawable/ic_lockscreen_ime + @*android:drawable/ic_mode_edit + @*android:drawable/ic_notifications_alerted + @*android:drawable/ic_phone + @*android:drawable/ic_qs_airplane + @*android:drawable/ic_qs_auto_rotate + @*android:drawable/ic_qs_battery_saver + @*android:drawable/ic_qs_bluetooth + @*android:drawable/ic_qs_dnd + @*android:drawable/ic_qs_flashlight + @*android:drawable/ic_qs_night_display_on + @*android:drawable/ic_qs_ui_mode_night + @*android:drawable/ic_restart + @*android:drawable/ic_screenshot + @*android:drawable/ic_settings_bluetooth + @*android:drawable/ic_signal_cellular_0_4_bar + @*android:drawable/ic_signal_cellular_0_5_bar + @*android:drawable/ic_signal_cellular_1_4_bar + @*android:drawable/ic_signal_cellular_1_5_bar + @*android:drawable/ic_signal_cellular_2_4_bar + @*android:drawable/ic_signal_cellular_2_5_bar + @*android:drawable/ic_signal_cellular_3_4_bar + @*android:drawable/ic_signal_cellular_3_5_bar + @*android:drawable/ic_signal_cellular_4_4_bar + @*android:drawable/ic_signal_cellular_4_5_bar + @*android:drawable/ic_signal_cellular_5_5_bar + @*android:drawable/ic_signal_location + @*android:drawable/ic_wifi_signal_0 + @*android:drawable/ic_wifi_signal_1 + @*android:drawable/ic_wifi_signal_2 + @*android:drawable/ic_wifi_signal_3 + @*android:drawable/ic_wifi_signal_4 + @*android:drawable/perm_group_activity_recognition + @*android:drawable/perm_group_aural + @*android:drawable/perm_group_calendar + @*android:drawable/perm_group_call_log + @*android:drawable/perm_group_camera + @*android:drawable/perm_group_contacts + @*android:drawable/perm_group_location + @*android:drawable/perm_group_microphone + @*android:drawable/perm_group_phone_calls + @*android:drawable/perm_group_sensors + @*android:drawable/perm_group_sms + @*android:drawable/perm_group_storage + @*android:drawable/perm_group_visual + + diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index f11adef8179361df630b01fe4fa6eabcfc1504ae..7d2e32ab08d3af04e5cdfdb8f385ea6ef726e925 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -191,7 +191,7 @@ public class TransactionParcelTests { PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); FixedRotationAdjustments fixedRotationAdjustments = new FixedRotationAdjustments( - Surface.ROTATION_90, DisplayCutout.NO_CUTOUT); + Surface.ROTATION_90, 1920, 1080, DisplayCutout.NO_CUTOUT); LaunchActivityItem item = LaunchActivityItem.obtain(intent, ident, activityInfo, config(), overrideConfig, compat, referrer, null /* voiceInteractor */, @@ -351,7 +351,8 @@ public class TransactionParcelTests { ClientTransaction transaction = ClientTransaction.obtain(new StubAppThread(), null /* activityToken */); transaction.addCallback(FixedRotationAdjustmentsItem.obtain(new Binder(), - new FixedRotationAdjustments(Surface.ROTATION_270, DisplayCutout.NO_CUTOUT))); + new FixedRotationAdjustments(Surface.ROTATION_270, 1920, 1080, + DisplayCutout.NO_CUTOUT))); writeAndPrepareForReading(transaction); diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java index 777f4a3e03a8ba2872cca9522fbc651093ecbeca..de81ff4d0ca59a1395beccb9de93960c231c6324 100644 --- a/core/tests/coretests/src/android/content/ContextTest.java +++ b/core/tests/coretests/src/android/content/ContextTest.java @@ -19,6 +19,7 @@ package android.content; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.google.common.truth.Truth.assertThat; @@ -188,19 +189,38 @@ public class ContextTest { assertFalse(wrapper.isUiContext()); - wrapper = new ContextWrapper(new TestUiContext()); + wrapper = new ContextWrapper(getUiContext()); assertTrue(wrapper.isUiContext()); } - private static class TestUiContext extends ContextWrapper { - TestUiContext() { - super(null /* base */); - } + @Test + public void testIsUiContext_UiContextDerivedContext() { + final Context uiContext = getUiContext(); + Context context = uiContext.createAttributionContext(null /* attributionTag */); - @Override - public boolean isUiContext() { - return true; - } + assertTrue(context.isUiContext()); + + context = uiContext.createConfigurationContext(new Configuration()); + + assertTrue(context.isUiContext()); + } + + @Test + public void testIsUiContext_UiContextDerivedDisplayContext() { + final Context uiContext = getUiContext(); + final Display secondaryDisplay = + getSecondaryDisplay(uiContext.getSystemService(DisplayManager.class)); + final Context context = uiContext.createDisplayContext(secondaryDisplay); + + assertFalse(context.isUiContext()); + } + + private Context getUiContext() { + final Context appContext = ApplicationProvider.getApplicationContext(); + final DisplayManager displayManager = appContext.getSystemService(DisplayManager.class); + final Display display = displayManager.getDisplay(DEFAULT_DISPLAY); + return appContext.createDisplayContext(display) + .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */); } } diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java index daf613976358ec2aaa2a355699a93a3fd064d2e6..0f6284d22d1067ff6760bdddeeb665e4eaad42ac 100644 --- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java +++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java @@ -247,6 +247,25 @@ public class VirtualDisplayTest extends AndroidTestCase { assertDisplayUnregistered(display); } + /** + * Ensures that an application can create a trusted virtual display with the permission + * {@code ADD_TRUSTED_DISPLAY}. + */ + public void testTrustedVirtualDisplay() throws Exception { + VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME, + WIDTH, HEIGHT, DENSITY, mSurface, + DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED); + assertNotNull("virtual display must not be null", virtualDisplay); + + Display display = virtualDisplay.getDisplay(); + try { + assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_TRUSTED); + } finally { + virtualDisplay.release(); + } + assertDisplayUnregistered(display); + } + private void assertDisplayRegistered(Display display, int flags) { assertNotNull("display object must not be null", display); assertTrue("display must be valid", display.isValid()); diff --git a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java index 2fc42e91a8cc8eff323a927074e3ef672476577c..3cf1722d49d368bd61c3debc095380298e094368 100644 --- a/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java +++ b/core/tests/coretests/src/android/view/DisplayAdjustmentsTests.java @@ -77,8 +77,10 @@ public class DisplayAdjustmentsTests { final int realRotation = Surface.ROTATION_0; final int fixedRotation = Surface.ROTATION_90; - mDisplayAdjustments.setFixedRotationAdjustments( - new FixedRotationAdjustments(fixedRotation, null /* cutout */)); + final int appWidth = 1080; + final int appHeight = 1920; + mDisplayAdjustments.setFixedRotationAdjustments(new FixedRotationAdjustments( + fixedRotation, appWidth, appHeight, null /* cutout */)); final int w = 1000; final int h = 2000; @@ -95,13 +97,21 @@ public class DisplayAdjustmentsTests { metrics.heightPixels = metrics.noncompatHeightPixels = h; final DisplayMetrics flippedMetrics = new DisplayMetrics(); - flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = h; + // The physical dpi should not be adjusted. + flippedMetrics.xdpi = flippedMetrics.noncompatXdpi = w; flippedMetrics.widthPixels = flippedMetrics.noncompatWidthPixels = h; - flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = w; + flippedMetrics.ydpi = flippedMetrics.noncompatYdpi = h; flippedMetrics.heightPixels = flippedMetrics.noncompatHeightPixels = w; mDisplayAdjustments.adjustMetrics(metrics, realRotation); assertEquals(flippedMetrics, metrics); + + mDisplayAdjustments.adjustGlobalAppMetrics(metrics); + + assertEquals(appWidth, metrics.widthPixels); + assertEquals(appWidth, metrics.noncompatWidthPixels); + assertEquals(appHeight, metrics.heightPixels); + assertEquals(appHeight, metrics.noncompatHeightPixels); } } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 48695aa5a32918b2a33e8c7c991376097f875392..de128ad6d78ea3825395278f8b894e56d11e95c7 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -41,8 +41,11 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; @@ -125,7 +128,7 @@ public class InsetsControllerTest { } mTestClock = new OffsettableClock(); mTestHandler = new TestHandler(null, mTestClock); - mTestHost = new TestHost(mViewRoot); + mTestHost = spy(new TestHost(mViewRoot)); mController = new InsetsController(mTestHost, (controller, type) -> { if (type == ITYPE_IME) { return new InsetsSourceConsumer(type, controller.getState(), @@ -760,6 +763,99 @@ public class InsetsControllerTest { }); } + @Test + public void testInsetsChangedCount_controlSystemBars() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + prepareControls(); + + // Hiding visible system bars should only causes insets change once for each bar. + clearInvocations(mTestHost); + mController.hide(statusBars() | navigationBars()); + verify(mTestHost, times(2)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after hiding system bars. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Showing invisible system bars should only causes insets change once for each bar. + clearInvocations(mTestHost); + mController.show(statusBars() | navigationBars()); + verify(mTestHost, times(2)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after showing system bars. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + }); + } + + @Test + public void testInsetsChangedCount_controlIme() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + prepareControls(); + + // Showing invisible ime should only causes insets change once. + clearInvocations(mTestHost); + mController.show(ime(), true /* fromIme */); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after showing ime. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Hiding visible ime should only causes insets change once. + clearInvocations(mTestHost); + mController.hide(ime()); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after hiding ime. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + }); + } + + @Test + public void testInsetsChangedCount_onStateChanged() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final InsetsState localState = mController.getState(); + + // Changing status bar frame should cause notifyInsetsChanged. + clearInvocations(mTestHost); + InsetsState newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_STATUS_BAR).getFrame().bottom++; + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Changing status bar visibility should cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_STATUS_BAR).setVisible(false); + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Changing invisible IME frame should not cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_IME).getFrame().top--; + mController.onStateChanged(newState); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Changing IME visibility should cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_IME).setVisible(true); + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + }); + } + private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT, @@ -792,7 +888,7 @@ public class InsetsControllerTest { return controls; } - private static class TestHost extends ViewRootInsetsControllerHost { + public static class TestHost extends ViewRootInsetsControllerHost { private InsetsState mModifiedState = new InsetsState(); diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index c7d835ca7c7e4617294e8fe2cd3a0124d77a35e0..576cd78606d7c4984b94862ba1dd80e32248c10f 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -123,6 +123,24 @@ public class InsetsStateTest { } } + @Test + public void testCalculateInsets_extraNavRightClimateTop() throws Exception { + try (final InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(ITYPE_CLIMATE_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(ITYPE_CLIMATE_BAR).setVisible(true); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null); + // ITYPE_CLIMATE_BAR is a type of status bar and ITYPE_EXTRA_NAVIGATION_BAR is a type + // of navigation bar. + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); + } + } + @Test public void testCalculateInsets_imeIgnoredWithoutAdjustResize() { try (final InsetsModeSession session = @@ -331,6 +349,8 @@ public class InsetsStateTest { public void testGetDefaultVisibility() { assertTrue(InsetsState.getDefaultVisibility(ITYPE_STATUS_BAR)); assertTrue(InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR)); + assertTrue(InsetsState.getDefaultVisibility(ITYPE_CLIMATE_BAR)); + assertTrue(InsetsState.getDefaultVisibility(ITYPE_EXTRA_NAVIGATION_BAR)); assertTrue(InsetsState.getDefaultVisibility(ITYPE_CAPTION_BAR)); assertFalse(InsetsState.getDefaultVisibility(ITYPE_IME)); } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 5c16772488d0937fe1164844bea0224f8157256d..4cf6715ba0cae392c5134580c8c126515973cd32 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -24,6 +24,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; @@ -117,7 +118,15 @@ public class ViewRootImplTest { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); - // A window which fits system bars must fit IME, unless its type is toast or system alert. + assertEquals(Type.systemBars(), attrs.getFitInsetsTypes()); + } + + @Test + public void adjustLayoutParamsForCompatibility_fitSystemBarsAndIme() { + final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION); + attrs.softInputMode |= SOFT_INPUT_ADJUST_RESIZE; + ViewRootImpl.adjustLayoutParamsForCompatibility(attrs); + assertEquals(Type.systemBars() | Type.ime(), attrs.getFitInsetsTypes()); } diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index df2946c97d20bd8d8f0ffda20ed88496dd16d055..c37a34a685498f01c512cc8e570452bcba0b2445 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -200,6 +200,38 @@ public class EditorCursorDragTest { onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); } + @Test + public void testCursorDrag_diagonal_thresholdConfig() throws Throwable { + TextView tv = mActivity.findViewById(R.id.textview); + Editor editor = tv.getEditorForTesting(); + + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= 9; i++) { + sb.append("here is some text").append(i).append("\n"); + } + sb.append(Strings.repeat("abcdefghij\n", 400)).append("Last"); + String text = sb.toString(); + onView(withId(R.id.textview)).perform(replaceText(text)); + + int index = text.indexOf("text9"); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); + + // Configure the drag direction threshold to require the drag to be exactly horizontal. With + // this set, a swipe that is slightly off horizontal should not trigger cursor drag. + editor.setCursorDragMinAngleFromVertical(90); + int startIdx = text.indexOf("5"); + int endIdx = text.indexOf("here is some text3"); + onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index)); + + // Configure the drag direction threshold to require the drag to be 45 degrees or more from + // vertical. With this set, the same swipe gesture as above should now trigger cursor drag. + editor.setCursorDragMinAngleFromVertical(45); + onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(endIdx)); + } + @Test public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable { String text = "012345_aaa\n" diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java index 35fd4bd7dc14aa217446d9605dc4d38cf4b8f454..94f43def240de0528323b3d953e6237d9762d34f 100644 --- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java +++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java @@ -165,7 +165,7 @@ public class EditorTouchStateTest { long event2Time = 1001; MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f); mTouchState.update(event2, mConfig); - assertDrag(mTouchState, 20f, 30f, 0, 0, false); + assertDrag(mTouchState, 20f, 30f, 0, 0, 180f); // Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout. long event3Time = 5000; @@ -280,7 +280,7 @@ public class EditorTouchStateTest { long event3Time = 1002; MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY); mTouchState.update(event3, mConfig); - assertDrag(mTouchState, 20f, 30f, 0, 0, false); + assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE); // Simulate an ACTION_UP event. long event4Time = 1003; @@ -301,15 +301,15 @@ public class EditorTouchStateTest { long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 174f); mTouchState.update(event2, mConfig); - assertDrag(mTouchState, 0f, 0f, 0, 0, true); + assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f); // Simulate another ACTION_MOVE event that is horizontal from the original down event. - // The value of `isDragCloseToVertical` should NOT change since it should only reflect the - // initial direction of movement. + // The drag direction ratio should NOT change since it should only reflect the initial + // direction of movement. long event3Time = 1003; MotionEvent event3 = moveEvent(event1Time, event3Time, 200f, 0f); mTouchState.update(event3, mConfig); - assertDrag(mTouchState, 0f, 0f, 0, 0, true); + assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f); // Simulate an ACTION_UP event. long event4Time = 1004; @@ -330,15 +330,15 @@ public class EditorTouchStateTest { long event2Time = 1002; MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f); mTouchState.update(event2, mConfig); - assertDrag(mTouchState, 0f, 0f, 0, 0, false); + assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f); // Simulate another ACTION_MOVE event that is vertical from the original down event. - // The value of `isDragCloseToVertical` should NOT change since it should only reflect the - // initial direction of movement. + // The drag direction ratio should NOT change since it should only reflect the initial + // direction of movement. long event3Time = 1003; MotionEvent event3 = moveEvent(event1Time, event3Time, 0f, 200f); mTouchState.update(event3, mConfig); - assertDrag(mTouchState, 0f, 0f, 0, 0, false); + assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f); // Simulate an ACTION_UP event. long event4Time = 1004; @@ -374,7 +374,7 @@ public class EditorTouchStateTest { long event2Time = 1002; MotionEvent event2 = moveEvent(event2Time, event2Time, 200f, 30f); mTouchState.update(event2, mConfig); - assertDrag(mTouchState, 20f, 30f, 0, 0, false); + assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE); // Simulate an ACTION_CANCEL event. long event3Time = 1003; @@ -411,6 +411,84 @@ public class EditorTouchStateTest { assertSingleTap(mTouchState, 22f, 33f, 20f, 30f); } + @Test + public void testGetXYRatio() throws Exception { + doTestGetXYRatio(-1, 0.0f); + doTestGetXYRatio(0, 0.0f); + doTestGetXYRatio(30, 0.58f); + doTestGetXYRatio(45, 1.0f); + doTestGetXYRatio(60, 1.73f); + doTestGetXYRatio(90, Float.MAX_VALUE); + doTestGetXYRatio(91, Float.MAX_VALUE); + } + + private void doTestGetXYRatio(int angleFromVerticalInDegrees, float expectedXYRatioRounded) { + float result = EditorTouchState.getXYRatio(angleFromVerticalInDegrees); + String msg = String.format( + "%d deg should give an x/y ratio of %f; actual unrounded result is %f", + angleFromVerticalInDegrees, expectedXYRatioRounded, result); + float roundedResult = (result == 0.0f || result == Float.MAX_VALUE) ? result : + Math.round(result * 100) / 100f; + assertThat(msg, roundedResult, is(expectedXYRatioRounded)); + } + + @Test + public void testUpdate_dragDirection() throws Exception { + // Simulate moving straight up. + doTestDragDirection(100f, 100f, 100f, 50f, 0f); + + // Simulate moving straight down. + doTestDragDirection(100f, 100f, 100f, 150f, 0f); + + // Simulate moving straight left. + doTestDragDirection(100f, 100f, 50f, 100f, Float.MAX_VALUE); + + // Simulate moving straight right. + doTestDragDirection(100f, 100f, 150f, 100f, Float.MAX_VALUE); + + // Simulate moving up and right, < 45 deg from vertical. + doTestDragDirection(100f, 100f, 110f, 50f, 10f / 50f); + + // Simulate moving up and right, > 45 deg from vertical. + doTestDragDirection(100f, 100f, 150f, 90f, 50f / 10f); + + // Simulate moving down and right, < 45 deg from vertical. + doTestDragDirection(100f, 100f, 110f, 150f, 10f / 50f); + + // Simulate moving down and right, > 45 deg from vertical. + doTestDragDirection(100f, 100f, 150f, 110f, 50f / 10f); + + // Simulate moving down and left, < 45 deg from vertical. + doTestDragDirection(100f, 100f, 90f, 150f, 10f / 50f); + + // Simulate moving down and left, > 45 deg from vertical. + doTestDragDirection(100f, 100f, 50f, 110f, 50f / 10f); + + // Simulate moving up and left, < 45 deg from vertical. + doTestDragDirection(100f, 100f, 90f, 50f, 10f / 50f); + + // Simulate moving up and left, > 45 deg from vertical. + doTestDragDirection(100f, 100f, 50f, 90f, 50f / 10f); + } + + private void doTestDragDirection(float downX, float downY, float moveX, float moveY, + float expectedInitialDragDirectionXYRatio) { + EditorTouchState touchState = new EditorTouchState(); + + // Simulate an ACTION_DOWN event. + long event1Time = 1001; + MotionEvent event1 = downEvent(event1Time, event1Time, downX, downY); + touchState.update(event1, mConfig); + + // Simulate an ACTION_MOVE event. + long event2Time = 1002; + MotionEvent event2 = moveEvent(event1Time, event2Time, moveX, moveY); + touchState.update(event2, mConfig); + String msg = String.format("(%.0f,%.0f)=>(%.0f,%.0f)", downX, downY, moveX, moveY); + assertThat(msg, touchState.getInitialDragDirectionXYRatio(), + is(expectedInitialDragDirectionXYRatio)); + } + private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) { return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); } @@ -441,7 +519,7 @@ public class EditorTouchStateTest { } private static void assertDrag(EditorTouchState touchState, float lastDownX, - float lastDownY, float lastUpX, float lastUpY, boolean isDragCloseToVertical) { + float lastDownY, float lastUpX, float lastUpY, float initialDragDirectionXYRatio) { assertThat(touchState.getLastDownX(), is(lastDownX)); assertThat(touchState.getLastDownY(), is(lastDownY)); assertThat(touchState.getLastUpX(), is(lastUpX)); @@ -451,7 +529,7 @@ public class EditorTouchStateTest { assertThat(touchState.isMultiTap(), is(false)); assertThat(touchState.isMultiTapInSameArea(), is(false)); assertThat(touchState.isMovedEnoughForDrag(), is(true)); - assertThat(touchState.isDragCloseToVertical(), is(isDragCloseToVertical)); + assertThat(touchState.getInitialDragDirectionXYRatio(), is(initialDragDirectionXYRatio)); } private static void assertMultiTap(EditorTouchState touchState, @@ -467,6 +545,5 @@ public class EditorTouchStateTest { || multiTapStatus == MultiTapStatus.TRIPLE_CLICK)); assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea)); assertThat(touchState.isMovedEnoughForDrag(), is(false)); - assertThat(touchState.isDragCloseToVertical(), is(false)); } } diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index a5a2221e553241b70ccda4083c1eeba703ff76d3..06f1dae30cd3404778b2814540baf3e1fc9f0830 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -35,10 +35,12 @@ + + diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index ce6deeab87faf80004fc183416c77c82b8b03bfc..6555fe93c81f46cde5619a44516aad3a86c881b9 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -143,6 +143,10 @@ applications that come with the platform + + + + diff --git a/data/sounds/effects/ChargingStarted.ogg b/data/sounds/effects/ChargingStarted.ogg index f09e273ea5ac5e2f9d5562c0f177d704fa991ab3..9526b08d9b3cd6aa5179b746c1448d19bd2ceb5e 100644 Binary files a/data/sounds/effects/ChargingStarted.ogg and b/data/sounds/effects/ChargingStarted.ogg differ diff --git a/data/sounds/effects/ogg/ChargingStarted.ogg b/data/sounds/effects/ogg/ChargingStarted.ogg index f09e273ea5ac5e2f9d5562c0f177d704fa991ab3..9526b08d9b3cd6aa5179b746c1448d19bd2ceb5e 100644 Binary files a/data/sounds/effects/ogg/ChargingStarted.ogg and b/data/sounds/effects/ogg/ChargingStarted.ogg differ diff --git a/data/sounds/effects/ogg/ChargingStarted_48k.ogg b/data/sounds/effects/ogg/ChargingStarted_48k.ogg index f09e273ea5ac5e2f9d5562c0f177d704fa991ab3..9526b08d9b3cd6aa5179b746c1448d19bd2ceb5e 100644 Binary files a/data/sounds/effects/ogg/ChargingStarted_48k.ogg and b/data/sounds/effects/ogg/ChargingStarted_48k.ogg differ diff --git a/drm/jni/Android.bp b/drm/jni/Android.bp index 1e33f0ea50942885f99ffdb2be6f1749ee0101a5..68757d86fb89fc290b3d6ec2f58ba920a8b9efd2 100644 --- a/drm/jni/Android.bp +++ b/drm/jni/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { shared_libs: [ "libdrmframework", + "libdrmframeworkcommon", "liblog", "libutils", "libandroid_runtime", diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt index 70dedb8179b0c90b8d820369cd28c895ee8ac23f..d8af726ffa72e01909bbd86a999d8d1f34236b39 100644 --- a/framework-jarjar-rules.txt +++ b/framework-jarjar-rules.txt @@ -1,6 +1,2 @@ rule android.hidl.** android.internal.hidl.@1 rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1 - -# Hide media mainline module implementation classes to avoid collisions with -# app-bundled ExoPlayer classes. -rule com.google.android.exoplayer2.** android.media.internal.exo.@1 diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp index 4f4364f72fefedadf3b4aa93cc7c6a3eeb30be52..7fbbb61e469d44ffb582a02cd1bdbf742fab164a 100644 --- a/libs/WindowManager/Jetpack/Android.bp +++ b/libs/WindowManager/Jetpack/Android.bp @@ -24,14 +24,14 @@ java_library { static_libs: ["window-sidecar"], installable: true, sdk_version: "core_platform", - vendor: true, + system_ext_specific: true, libs: ["framework", "androidx.annotation_annotation",], required: ["androidx.window.sidecar.xml",], } prebuilt_etc { name: "androidx.window.sidecar.xml", - vendor: true, + system_ext_specific: true, sub_dir: "permissions", src: "androidx.window.sidecar.xml", filename_from_src: true, diff --git a/libs/WindowManager/Jetpack/androidx.window.sidecar.xml b/libs/WindowManager/Jetpack/androidx.window.sidecar.xml index f88a5f4ae039490556f0c12dbe05a7444452506c..359e69fd9bc1a85074c2d178e8dc497859568503 100644 --- a/libs/WindowManager/Jetpack/androidx.window.sidecar.xml +++ b/libs/WindowManager/Jetpack/androidx.window.sidecar.xml @@ -17,5 +17,5 @@ + file="/system_ext/framework/androidx.window.sidecar.jar"/> diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 75ea0cbada92b6c56d3b3cc0a5e7fdace2fb073b..7ed5b579ebb4fa3e14d3fb3ce29005ad173e2eb0 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -45,9 +45,9 @@ import com.android.internal.location.ProviderProperties; interface ILocationManager { Location getLastLocation(in LocationRequest request, String packageName, String featureId); - boolean getCurrentLocation(in LocationRequest request, - in ICancellationSignal cancellationSignal, in ILocationListener listener, - String packageName, String featureId, String listenerId); + @nullable ICancellationSignal getCurrentLocation(in LocationRequest request, + in ILocationListener listener, String packageName, String featureId, + String listenerId); void requestLocationUpdates(in LocationRequest request, in ILocationListener listener, in PendingIntent intent, String packageName, String featureId, String listenerId); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 0c7d96d9f1361f0bba054b00a45f35453172b012..33c69511d273151761a325a3c1d4a0ff5c442ab8 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -724,16 +724,15 @@ public class LocationManager { cancellationSignal.throwIfCanceled(); } - ICancellationSignal remoteCancellationSignal = CancellationSignal.createTransport(); - try { - if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal, - transport, mContext.getPackageName(), mContext.getAttributionTag(), - transport.getListenerId())) { + ICancellationSignal cancelRemote = mService.getCurrentLocation( + currentLocationRequest, transport, mContext.getPackageName(), + mContext.getAttributionTag(), transport.getListenerId()); + if (cancelRemote != null) { transport.register(mContext.getSystemService(AlarmManager.class), - remoteCancellationSignal); + cancellationSignal, cancelRemote); if (cancellationSignal != null) { - cancellationSignal.setOnCancelListener(transport::cancel); + cancellationSignal.setRemote(cancelRemote); } } else { transport.fail(); @@ -2535,7 +2534,7 @@ public class LocationManager { } private static class GetCurrentLocationTransport extends ILocationListener.Stub implements - AlarmManager.OnAlarmListener { + AlarmManager.OnAlarmListener, CancellationSignal.OnCancelListener { @GuardedBy("this") @Nullable @@ -2567,6 +2566,7 @@ public class LocationManager { } public synchronized void register(AlarmManager alarmManager, + CancellationSignal cancellationSignal, ICancellationSignal remoteCancellationSignal) { if (mConsumer == null) { return; @@ -2580,10 +2580,18 @@ public class LocationManager { this, null); + if (cancellationSignal != null) { + cancellationSignal.setOnCancelListener(this); + } + mRemoteCancellationSignal = remoteCancellationSignal; } - public void cancel() { + @Override + public void onCancel() { + synchronized (this) { + mRemoteCancellationSignal = null; + } remove(); } @@ -2632,11 +2640,6 @@ public class LocationManager { @Override public void onLocationChanged(Location location) { - synchronized (this) { - // save ourselves a pointless x-process call to cancel the location request - mRemoteCancellationSignal = null; - } - deliverResult(location); } @@ -3034,7 +3037,7 @@ public class LocationManager { protected GnssRequest merge(@NonNull List requests) { Preconditions.checkArgument(!requests.isEmpty()); for (GnssRequest request : requests) { - if (request.isFullTracking()) { + if (request != null && request.isFullTracking()) { return request; } } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 655d100cbb4c0b80dcbc57cefc7905f60d30c9af..b2c2c4b1bbb499b638fd3d3df858b02cc6e0a81c 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -808,7 +808,8 @@ public class AudioTrack extends PlayerBase int initResult = native_setup(new WeakReference(this), mAttributes, sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat, mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/, - offload, encapsulationMode, tunerConfiguration); + offload, encapsulationMode, tunerConfiguration, + getCurrentOpPackageName()); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED @@ -894,7 +895,8 @@ public class AudioTrack extends PlayerBase nativeTrackInJavaObj, false /*offload*/, ENCAPSULATION_MODE_NONE, - null /* tunerConfiguration */); + null /* tunerConfiguration */, + "" /* opPackagename */); if (initResult != SUCCESS) { loge("Error code "+initResult+" when initializing AudioTrack."); return; // with mState == STATE_UNINITIALIZED @@ -4069,7 +4071,8 @@ public class AudioTrack extends PlayerBase Object /*AudioAttributes*/ attributes, int[] sampleRate, int channelMask, int channelIndexMask, int audioFormat, int buffSizeInBytes, int mode, int[] sessionId, long nativeAudioTrack, - boolean offload, int encapsulationMode, Object tunerConfiguration); + boolean offload, int encapsulationMode, Object tunerConfiguration, + @NonNull String opPackageName); private native final void native_finalize(); diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 5fce5ee9407df2d12d5188b3a9ea10faf19b9e30..3293c407ed4596be87775c322f37ed3dc0f5c524 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -70,6 +70,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.CRC32; @@ -2095,7 +2096,10 @@ public class ExifInterface { try { // Move the original file to temporary file. if (mFilename != null) { - tempFile = new File(mFilename + ".tmp"); + String parent = originalFile.getParent(); + String name = originalFile.getName(); + String tempPrefix = UUID.randomUUID().toString() + "_"; + tempFile = new File(parent, tempPrefix + name); if (!originalFile.renameTo(tempFile)) { throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath()); } diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index e571b6868e68bda4d9ce060d2c7938c20416e79d..559786cc70932c72d413040e2890bccb6dd98f20 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -673,7 +673,8 @@ public class MediaPlayer extends PlayerBase /* Native setup requires a weak reference to our object. * It's easier to create it here than in C++. */ - native_setup(new WeakReference(this)); + native_setup(new WeakReference(this), + getCurrentOpPackageName()); baseRegisterPlayer(); } @@ -2379,7 +2380,7 @@ public class MediaPlayer extends PlayerBase private native final int native_setMetadataFilter(Parcel request); private static native final void native_init(); - private native final void native_setup(Object mediaplayer_this); + private native void native_setup(Object mediaplayerThis, @NonNull String opPackageName); private native final void native_finalize(); /** diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index ee8f1b3eec7728f4c51cb0c4aef0780cbe9ccdb3..df5e85edbc3055307fb875eb3bd1d16aa05daaf5 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -27,6 +27,7 @@ import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -622,4 +623,8 @@ public abstract class PlayerBase { Log.w(className, "See the documentation of " + opName + " for what to use instead with " + "android.media.AudioAttributes to qualify your playback use case"); } + + protected String getCurrentOpPackageName() { + return TextUtils.emptyIfNull(ActivityThread.currentOpPackageName()); + } } diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 3d27e4b591fdf67bdbccf95a0564604f6e20bb81..84ec93d4c36b96f10f59b3f029b64ddb3602dfbe 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -185,7 +185,7 @@ public final class MediaBrowser { boolean bound = false; try { bound = mContext.bindService(intent, mServiceConnection, - Context.BIND_AUTO_CREATE); + Context.BIND_AUTO_CREATE | Context.BIND_INCLUDE_CAPABILITIES); } catch (Exception ex) { Log.e(TAG, "Failed binding to service " + mServiceComponent); } diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 82b746f6a9e50ead47c4e5f78910955e307a740c..d63b1adff5a0974b8f678a995eb0f308b6a9e5a8 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -33,6 +33,7 @@ #include #include "jni.h" #include +#include #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" #include "android_runtime/Log.h" @@ -944,10 +945,12 @@ android_media_MediaPlayer_native_init(JNIEnv *env) } static void -android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) +android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jstring opPackageName) { ALOGV("native_setup"); - sp mp = new MediaPlayer(); + ScopedUtfChars opPackageNameStr(env, opPackageName); + sp mp = new MediaPlayer(opPackageNameStr.c_str()); if (mp == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; @@ -1403,7 +1406,7 @@ static const JNINativeMethod gMethods[] = { {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer_native_init}, - {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, + {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id}, {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id}, diff --git a/packages/CarSystemUI/TEST_MAPPING b/packages/CarSystemUI/TEST_MAPPING index 6056ddfc0bc73571a850c540fee7e13b19c77213..c18a12aeb2aaabd87fb89fac810c2f2e5c31165b 100644 --- a/packages/CarSystemUI/TEST_MAPPING +++ b/packages/CarSystemUI/TEST_MAPPING @@ -8,5 +8,16 @@ } ] } + ], + + "carsysui-presubmit": [ + { + "name": "CarSystemUITests", + "options" : [ + { + "include-annotation": "com.android.systemui.car.CarSystemUiTest" + } + ] + } ] } diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml index 8b235e6f246e418966d931857abea2738e474b75..d57875f8daba308c33241686e6a803e5a1da436e 100644 --- a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml @@ -53,7 +53,7 @@ android:textColor="?attr/wallpaperTextColor" android:textAppearance="?android:attr/textAppearanceMedium" android:imeOptions="flagForceAscii|actionDone" - android:maxLength="@integer/password_text_view_scale" + android:maxLength="@integer/password_max_length" /> - + - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/CarSystemUI/res/layout/super_status_bar.xml b/packages/CarSystemUI/res/layout/super_status_bar.xml deleted file mode 100644 index d93f62f8809d687a6864c21cba8a9eddf2085271..0000000000000000000000000000000000000000 --- a/packages/CarSystemUI/res/layout/super_status_bar.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml index 2dc499c160c6e50b899340095fc1221a0d6cda96..e7295aa6383d00cf2fc9a3c6629c35e0809e38ed 100644 --- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml +++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml @@ -22,12 +22,11 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/> true - + true false false true + + + + + + 0 + 2 + 3 + 1 + + + + + 1 + 0 + 0 + 10 + + + false + + @*android:bool/config_automotiveHideNavBarForKeyboard + + false + false + false diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index cb321cdc6c4dcc07e1fb48140c8e9c54a5448123..e8ac9e14eca16627dda099ec08dc6af7b1383217 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -81,6 +81,21 @@ 96dp 128dp + + 48dp + + 15dp + + 24dp + + 12dp + + 6dp + + 4dp + + 12dp + @dimen/car_primary_icon_size @*android:dimen/car_single_line_list_item_height @@ -179,6 +194,12 @@ 760dp 96dp 96dp + + @*android:dimen/navigation_bar_height + + @*android:dimen/status_bar_height 420dp diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java index 34afb132805ca544864cec0f45a490eac5555183..b3102e248ab2add5d7ef7c1ff087d3c1a1c9f650 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIBinder.java @@ -21,8 +21,8 @@ import com.android.systemui.bubbles.dagger.BubbleModule; import com.android.systemui.car.navigationbar.CarNavigationBar; import com.android.systemui.car.notification.CarNotificationModule; import com.android.systemui.car.sideloaded.SideLoadedAppController; -import com.android.systemui.car.statusbar.CarStatusBar; -import com.android.systemui.car.statusbar.CarStatusBarModule; +import com.android.systemui.car.statusbar.UnusedStatusBar; +import com.android.systemui.car.statusbar.UnusedStatusBarModule; import com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier; import com.android.systemui.car.volume.VolumeUI; import com.android.systemui.car.window.OverlayWindowModule; @@ -39,7 +39,6 @@ import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.notification.InstantAppNotifier; import com.android.systemui.statusbar.notification.dagger.NotificationsModule; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; import com.android.systemui.toast.ToastUI; import com.android.systemui.util.leak.GarbageMonitor; @@ -50,9 +49,9 @@ import dagger.multibindings.ClassKey; import dagger.multibindings.IntoMap; /** Binder for car specific {@link SystemUI} modules. */ -@Module(includes = {RecentsModule.class, CarStatusBarModule.class, NotificationsModule.class, +@Module(includes = {RecentsModule.class, NotificationsModule.class, BubbleModule.class, KeyguardModule.class, OverlayWindowModule.class, - CarNotificationModule.class}) + CarNotificationModule.class, UnusedStatusBarModule.class}) public abstract class CarSystemUIBinder { /** Inject into AuthController. */ @Binds @@ -155,19 +154,7 @@ public abstract class CarSystemUIBinder { @Binds @IntoMap @ClassKey(StatusBar.class) - public abstract SystemUI bindsStatusBar(CarStatusBar sysui); - - /** Inject into TvStatusBar. */ - @Binds - @IntoMap - @ClassKey(TvStatusBar.class) - public abstract SystemUI bindsTvStatusBar(TvStatusBar sysui); - - /** Inject into StatusBarGoogle. */ - @Binds - @IntoMap - @ClassKey(CarStatusBar.class) - public abstract SystemUI bindsCarStatusBar(CarStatusBar sysui); + public abstract SystemUI bindsStatusBar(UnusedStatusBar sysui); /** Inject into VolumeUI. */ @Binds diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 59d6ed67b5528b9af5cc740289a0f4b97cefd5b5..0e3c7f31886b74ff63491f9dbfe8521cdada7312 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -28,10 +28,9 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; import com.android.systemui.car.keyguard.CarKeyguardViewController; -import com.android.systemui.car.statusbar.CarStatusBar; -import com.android.systemui.car.statusbar.CarStatusBarKeyguardViewManager; import com.android.systemui.car.statusbar.DozeServiceHost; import com.android.systemui.car.statusbar.DummyNotificationShadeWindowController; +import com.android.systemui.car.statusbar.UnusedStatusBar; import com.android.systemui.car.volume.CarVolumeDialogComponent; import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dagger.qualifiers.Background; @@ -60,13 +59,14 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.ShadeControllerImpl; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryControllerImpl; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.volume.VolumeDialogComponent; +import com.android.systemui.wm.DisplayImeController; +import com.android.systemui.wm.DisplaySystemBarsController; import javax.inject.Named; import javax.inject.Singleton; @@ -97,6 +97,10 @@ public abstract class CarSystemUIModule { groupManager, configurationController); } + @Binds + abstract DisplayImeController bindDisplayImeController( + DisplaySystemBarsController displaySystemBarsController); + @Singleton @Provides @Named(LEAK_REPORT_EMAIL_NAME) @@ -135,7 +139,7 @@ public abstract class CarSystemUIModule { @Binds @Singleton - public abstract QSFactory provideQSFactory(QSFactoryImpl qsFactoryImpl); + public abstract QSFactory bindQSFactory(QSFactoryImpl qsFactoryImpl); @Binds abstract DockManager bindDockManager(DockManagerImpl dockManager); @@ -151,17 +155,10 @@ public abstract class CarSystemUIModule { abstract SystemUIRootComponent bindSystemUIRootComponent( CarSystemUIRootComponent systemUIRootComponent); - @Binds - public abstract StatusBar bindStatusBar(CarStatusBar statusBar); - @Binds abstract VolumeDialogComponent bindVolumeDialogComponent( CarVolumeDialogComponent carVolumeDialogComponent); - @Binds - abstract StatusBarKeyguardViewManager bindStatusBarKeyguardViewManager( - CarStatusBarKeyguardViewManager keyguardViewManager); - @Binds abstract KeyguardViewController bindKeyguardViewController( CarKeyguardViewController carKeyguardViewController); @@ -180,4 +177,7 @@ public abstract class CarSystemUIModule { @Binds abstract DozeHost bindDozeHost(DozeServiceHost dozeServiceHost); + + @Binds + abstract StatusBar bindStatusBar(UnusedStatusBar statusBar); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5f593b06c51152a7fd17354436360a5ad427fd85 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.car; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotates that a test class should be run as part of CarSystemUI presubmit + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface CarSystemUiTest { +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java index 69766cc6c0d0a1fdaead0147c025cf8ac79e5873..ec018f9bb62e568ab3689d7c322b311afb8c1aec 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -21,10 +21,13 @@ import android.car.user.CarUserManager; import android.content.Context; import android.os.Bundle; import android.os.Handler; +import android.os.UserHandle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewRootImpl; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; import androidx.annotation.VisibleForTesting; @@ -61,7 +64,7 @@ import dagger.Lazy; public class CarKeyguardViewController extends OverlayViewController implements KeyguardViewController { private static final String TAG = "CarKeyguardViewController"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private final Context mContext; private final Handler mHandler; @@ -75,9 +78,10 @@ public class CarKeyguardViewController extends OverlayViewController implements private final DismissCallbackRegistry mDismissCallbackRegistry; private final ViewMediatorCallback mViewMediatorCallback; private final CarNavigationBarController mCarNavigationBarController; + private final InputMethodManager mInputMethodManager; // Needed to instantiate mBouncer. - private final KeyguardBouncer.BouncerExpansionCallback - mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() { + private final KeyguardBouncer.BouncerExpansionCallback mExpansionCallback = + new KeyguardBouncer.BouncerExpansionCallback() { @Override public void onFullyShown() { } @@ -96,7 +100,8 @@ public class CarKeyguardViewController extends OverlayViewController implements }; private final CarUserManager.UserLifecycleListener mUserLifecycleListener = (e) -> { if (e.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) { - revealKeyguardIfBouncerPrepared(); + UserHandle currentUser = e.getUserHandle(); + revealKeyguardIfBouncerPrepared(currentUser); } }; @@ -136,10 +141,17 @@ public class CarKeyguardViewController extends OverlayViewController implements mDismissCallbackRegistry = dismissCallbackRegistry; mViewMediatorCallback = viewMediatorCallback; mCarNavigationBarController = carNavigationBarController; + // TODO(b/169280588): Inject InputMethodManager instead. + mInputMethodManager = mContext.getSystemService(InputMethodManager.class); registerUserSwitchedListener(); } + @Override + protected boolean shouldShowNavigationBarInsets() { + return true; + } + @Override public void onFinishInflate() { mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, @@ -172,7 +184,6 @@ public class CarKeyguardViewController extends OverlayViewController implements mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false); mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true); start(); - getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ true); reset(/* hideBouncerWhenShowing= */ false); notifyKeyguardUpdateMonitor(); } @@ -187,7 +198,6 @@ public class CarKeyguardViewController extends OverlayViewController implements mBouncer.hide(/* destroyView= */ true); mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true); stop(); - getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false); mKeyguardStateController.notifyKeyguardDoneFading(); mHandler.post(mViewMediatorCallback::keyguardGone); notifyKeyguardUpdateMonitor(); @@ -232,7 +242,6 @@ public class CarKeyguardViewController extends OverlayViewController implements public void onCancelClicked() { if (mBouncer == null) return; - getOverlayViewGlobalStateController().setWindowFocusable(/* focusable= */ false); getOverlayViewGlobalStateController().setWindowNeedsInput(/* needsInput= */ false); mBouncer.hide(/* destroyView= */ true); @@ -361,9 +370,9 @@ public class CarKeyguardViewController extends OverlayViewController implements } /** - * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be - * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator} - * when a new user is selected. + * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be + * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator} + * when a new user is selected. */ public void hideKeyguardToPrepareBouncer() { getLayout().setVisibility(View.INVISIBLE); @@ -374,29 +383,41 @@ public class CarKeyguardViewController extends OverlayViewController implements mBouncer = keyguardBouncer; } - private void revealKeyguardIfBouncerPrepared() { + private void revealKeyguardIfBouncerPrepared(UserHandle currentUser) { int reattemptDelayMillis = 50; Runnable revealKeyguard = () -> { if (mBouncer == null) { if (DEBUG) { Log.d(TAG, "revealKeyguardIfBouncerPrepared: revealKeyguard request is ignored " - + "since the Bouncer has not been initialized yet."); + + "since the Bouncer has not been initialized yet."); } return; } if (!mBouncer.inTransit() || !mBouncer.isSecure()) { getLayout().setVisibility(View.VISIBLE); + updateCurrentUserForPasswordEntry(currentUser); } else { if (DEBUG) { Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared " + "yet so reattempting after " + reattemptDelayMillis + "ms."); } - mHandler.postDelayed(this::revealKeyguardIfBouncerPrepared, reattemptDelayMillis); + mHandler.postDelayed(() -> revealKeyguardIfBouncerPrepared(currentUser), + reattemptDelayMillis); } }; mHandler.post(revealKeyguard); } + private void updateCurrentUserForPasswordEntry(UserHandle currentUser) { + EditText passwordEntry = getLayout().findViewById(R.id.passwordEntry); + if (passwordEntry != null) { + mHandler.post(() -> { + mInputMethodManager.restartInput(passwordEntry); + passwordEntry.setTextOperationUser(currentUser); + }); + } + } + private void notifyKeyguardUpdateMonitor() { mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing); if (mBouncer != null) { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java index 37dfce4e16ce7bae843dc562d39ccaae68e5f45d..b6d251fbfe1695d7c0ce35220bcdcdb6edddacc9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java @@ -16,8 +16,6 @@ package com.android.systemui.car.navigationbar; -import static android.view.InsetsState.ITYPE_CLIMATE_BAR; -import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.containsType; @@ -28,13 +26,11 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARE import android.content.Context; import android.content.res.Resources; -import android.graphics.PixelFormat; import android.inputmethodservice.InputMethodService; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.view.Display; -import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsetsController; @@ -45,7 +41,6 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.RegisterStatusBarResult; import com.android.internal.view.AppearanceRegion; -import com.android.systemui.R; import com.android.systemui.SystemUI; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedListener; @@ -74,7 +69,6 @@ import dagger.Lazy; /** Navigation bars customized for the automotive use case. */ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks { - private final Resources mResources; private final CarNavigationBarController mCarNavigationBarController; private final SysuiDarkIconDispatcher mStatusBarIconController; @@ -91,12 +85,17 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final Lazy mIconControllerLazy; private final int mDisplayId; + private final SystemBarConfigs mSystemBarConfigs; private StatusBarSignalPolicy mSignalPolicy; private ActivityManagerWrapper mActivityManagerWrapper; // If the nav bar should be hidden when the soft keyboard is visible. - private boolean mHideNavBarForKeyboard; + private boolean mHideTopBarForKeyboard; + private boolean mHideLeftBarForKeyboard; + private boolean mHideRightBarForKeyboard; + private boolean mHideBottomBarForKeyboard; + private boolean mBottomNavBarVisible; // Nav bar views. @@ -139,7 +138,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks IStatusBarService barService, Lazy keyguardStateControllerLazy, Lazy iconPolicyLazy, - Lazy iconControllerLazy + Lazy iconControllerLazy, + SystemBarConfigs systemBarConfigs ) { super(context); mResources = resources; @@ -156,6 +156,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks mKeyguardStateControllerLazy = keyguardStateControllerLazy; mIconPolicyLazy = iconPolicyLazy; mIconControllerLazy = iconControllerLazy; + mSystemBarConfigs = systemBarConfigs; mDisplayId = context.getDisplayId(); } @@ -163,8 +164,13 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks @Override public void start() { // Set initial state. - mHideNavBarForKeyboard = mResources.getBoolean( - com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + mHideTopBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP); + mHideBottomBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide( + SystemBarConfigs.BOTTOM); + mHideLeftBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.LEFT); + mHideRightBarForKeyboard = mSystemBarConfigs.getHideForKeyboardBySide( + SystemBarConfigs.RIGHT); + mBottomNavBarVisible = false; // Connect into the status bar manager service @@ -342,100 +348,63 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private void buildNavBarContent() { mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser()); if (mTopNavigationBarView != null) { + mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView); mTopNavigationBarWindow.addView(mTopNavigationBarView); } mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser()); if (mBottomNavigationBarView != null) { + mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView); mBottomNavigationBarWindow.addView(mBottomNavigationBarView); } mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser()); if (mLeftNavigationBarView != null) { + mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView); mLeftNavigationBarWindow.addView(mLeftNavigationBarView); } mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser()); if (mRightNavigationBarView != null) { + mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView); mRightNavigationBarWindow.addView(mRightNavigationBarView); } } private void attachNavBarWindows() { - if (mTopNavigationBarWindow != null) { - int height = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_height); - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - height, - WindowManager.LayoutParams.TYPE_STATUS_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - lp.setTitle("TopCarNavigationBar"); - lp.windowAnimations = 0; - lp.gravity = Gravity.TOP; - mWindowManager.addView(mTopNavigationBarWindow, lp); - } - - if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) { - mBottomNavBarVisible = true; - int height = mResources.getDimensionPixelSize( - com.android.internal.R.dimen.navigation_bar_height); - - WindowManager.LayoutParams lp = new WindowManager.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - height, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - lp.setTitle("BottomCarNavigationBar"); - lp.windowAnimations = 0; - lp.gravity = Gravity.BOTTOM; - mWindowManager.addView(mBottomNavigationBarWindow, lp); - } - - if (mLeftNavigationBarWindow != null) { - int width = mResources.getDimensionPixelSize( - R.dimen.car_left_navigation_bar_width); - WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams( - width, ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - leftlp.setTitle("LeftCarNavigationBar"); - leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR}; - leftlp.setFitInsetsTypes(0); - leftlp.windowAnimations = 0; - leftlp.gravity = Gravity.LEFT; - mWindowManager.addView(mLeftNavigationBarWindow, leftlp); - } + mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide); + } - if (mRightNavigationBarWindow != null) { - int width = mResources.getDimensionPixelSize( - R.dimen.car_right_navigation_bar_width); - WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams( - width, ViewGroup.LayoutParams.MATCH_PARENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, - PixelFormat.TRANSLUCENT); - rightlp.setTitle("RightCarNavigationBar"); - rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR}; - rightlp.setFitInsetsTypes(0); - rightlp.windowAnimations = 0; - rightlp.gravity = Gravity.RIGHT; - mWindowManager.addView(mRightNavigationBarWindow, rightlp); + private void attachNavBarBySide(int side) { + switch(side) { + case SystemBarConfigs.TOP: + if (mTopNavigationBarWindow != null) { + mWindowManager.addView(mTopNavigationBarWindow, + mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP)); + } + break; + case SystemBarConfigs.BOTTOM: + if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) { + mBottomNavBarVisible = true; + + mWindowManager.addView(mBottomNavigationBarWindow, + mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM)); + } + break; + case SystemBarConfigs.LEFT: + if (mLeftNavigationBarWindow != null) { + mWindowManager.addView(mLeftNavigationBarWindow, + mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT)); + } + break; + case SystemBarConfigs.RIGHT: + if (mRightNavigationBarWindow != null) { + mWindowManager.addView(mRightNavigationBarWindow, + mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT)); + } + break; + default: + return; } } @@ -447,17 +416,30 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks @Override public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher) { - if (!mHideNavBarForKeyboard) { - return; - } - if (mContext.getDisplayId() != displayId) { return; } boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; - mCarNavigationBarController.setBottomWindowVisibility( - isKeyboardVisible ? View.GONE : View.VISIBLE); + + if (mHideTopBarForKeyboard) { + mCarNavigationBarController.setTopWindowVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); + } + + if (mHideBottomBarForKeyboard) { + mCarNavigationBarController.setBottomWindowVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); + } + + if (mHideLeftBarForKeyboard) { + mCarNavigationBarController.setLeftWindowVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); + } + if (mHideRightBarForKeyboard) { + mCarNavigationBarController.setRightWindowVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); + } } @Override diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java index ca780ae645c9988d53d18a426811207d314faf6b..e522d19249e36a2337d89149c0b496cb5813033d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java @@ -22,7 +22,6 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; -import com.android.systemui.R; import com.android.systemui.car.hvac.HvacController; import javax.inject.Inject; @@ -61,7 +60,8 @@ public class CarNavigationBarController { NavigationBarViewFactory navigationBarViewFactory, ButtonSelectionStateController buttonSelectionStateController, Lazy hvacControllerLazy, - ButtonRoleHolderController buttonRoleHolderController) { + ButtonRoleHolderController buttonRoleHolderController, + SystemBarConfigs systemBarConfigs) { mContext = context; mNavigationBarViewFactory = navigationBarViewFactory; mButtonSelectionStateController = buttonSelectionStateController; @@ -69,19 +69,17 @@ public class CarNavigationBarController { mButtonRoleHolderController = buttonRoleHolderController; // Read configuration. - mShowTop = mContext.getResources().getBoolean(R.bool.config_enableTopNavigationBar); - mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar); - mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar); - mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar); + mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP); + mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM); + mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT); + mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT); } /** * Hides all system bars. */ public void hideBars() { - if (mTopView != null) { - mTopView.setVisibility(View.GONE); - } + setTopWindowVisibility(View.GONE); setBottomWindowVisibility(View.GONE); setLeftWindowVisibility(View.GONE); setRightWindowVisibility(View.GONE); @@ -91,9 +89,7 @@ public class CarNavigationBarController { * Shows all system bars. */ public void showBars() { - if (mTopView != null) { - mTopView.setVisibility(View.VISIBLE); - } + setTopWindowVisibility(View.VISIBLE); setBottomWindowVisibility(View.VISIBLE); setLeftWindowVisibility(View.VISIBLE); setRightWindowVisibility(View.VISIBLE); @@ -135,6 +131,11 @@ public class CarNavigationBarController { return mShowRight ? mNavigationBarViewFactory.getRightWindow() : null; } + /** Toggles the top nav bar visibility. */ + public boolean setTopWindowVisibility(@View.Visibility int visibility) { + return setWindowVisibility(getTopWindow(), visibility); + } + /** Toggles the bottom nav bar visibility. */ public boolean setBottomWindowVisibility(@View.Visibility int visibility) { return setWindowVisibility(getBottomWindow(), visibility); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java index 029d4c7fa2fb4e07807218088346a75a00edf8ac..ab401bbf06bb9931b27aafcda663085adba45504 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import android.view.WindowInsets; import android.widget.LinearLayout; import com.android.systemui.Dependency; @@ -77,11 +76,6 @@ public class CarNavigationBarView extends LinearLayout { setFocusable(false); } - @Override - public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) { - return windowInsets; - } - // Used to forward touch events even if the touch was initiated from a child component @Override public boolean onInterceptTouchEvent(MotionEvent ev) { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java index d60bc418ece20343925aa18b8f8eefc78e2b5afe..adf8d4d5acf88ed6810a93ced99c16d9bc0df2b2 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java @@ -148,10 +148,9 @@ public class NavigationBarViewFactory { CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout, /* root= */ null); - // Include a FocusParkingView at the end. The rotary controller "parks" the focus here when - // the user navigates to another window. This is also used to prevent wrap-around which is - // why it must be first or last in Tab order. - view.addView(new FocusParkingView(mContext)); + // Include a FocusParkingView at the beginning. The rotary controller "parks" the focus here + // when the user navigates to another window. This is also used to prevent wrap-around. + view.addView(new FocusParkingView(mContext), 0); mCachedViewMap.put(type, view); return mCachedViewMap.get(type); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java new file mode 100644 index 0000000000000000000000000000000000000000..2efa2b3d48700ba4e3eaf6e69b67222460c1356f --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java @@ -0,0 +1,458 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.car.navigationbar; + +import android.annotation.IntDef; +import android.content.res.Resources; +import android.graphics.PixelFormat; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; +import android.view.Gravity; +import android.view.InsetsState; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.R; +import com.android.systemui.car.notification.BottomNotificationPanelViewMediator; +import com.android.systemui.car.notification.TopNotificationPanelViewMediator; +import com.android.systemui.dagger.qualifiers.Main; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the + * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration. + */ +@Singleton +public class SystemBarConfigs { + + private static final String TAG = SystemBarConfigs.class.getSimpleName(); + // The z-order from which system bars will start to appear on top of HUN's. + private static final int HUN_ZORDER = 10; + + @IntDef(value = {TOP, BOTTOM, LEFT, RIGHT}) + @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) + private @interface SystemBarSide { + } + + public static final int TOP = 0; + public static final int BOTTOM = 1; + public static final int LEFT = 2; + public static final int RIGHT = 3; + + /* + NOTE: The elements' order in the map below must be preserved as-is since the correct + corresponding values are obtained by the index. + */ + private static final int[] BAR_TYPE_MAP = { + InsetsState.ITYPE_STATUS_BAR, + InsetsState.ITYPE_NAVIGATION_BAR, + InsetsState.ITYPE_CLIMATE_BAR, + InsetsState.ITYPE_EXTRA_NAVIGATION_BAR + }; + + private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>(); + private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>(); + private static final Map<@SystemBarSide Integer, Integer> BAR_GESTURE_MAP = new ArrayMap<>(); + + private final Resources mResources; + private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap = + new ArrayMap<>(); + private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>(); + + private boolean mTopNavBarEnabled; + private boolean mBottomNavBarEnabled; + private boolean mLeftNavBarEnabled; + private boolean mRightNavBarEnabled; + + @Inject + public SystemBarConfigs(@Main Resources resources) { + mResources = resources; + + populateMaps(); + readConfigs(); + + checkEnabledBarsHaveUniqueBarTypes(); + checkSystemBarEnabledForNotificationPanel(); + checkHideBottomBarForKeyboardConfigSync(); + + setInsetPaddingsForOverlappingCorners(); + sortSystemBarSidesByZOrder(); + } + + protected WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) { + return mSystemBarConfigMap.get(side) != null + ? mSystemBarConfigMap.get(side).getLayoutParams() : null; + } + + protected boolean getEnabledStatusBySide(@SystemBarSide int side) { + switch (side) { + case TOP: + return mTopNavBarEnabled; + case BOTTOM: + return mBottomNavBarEnabled; + case LEFT: + return mLeftNavBarEnabled; + case RIGHT: + return mRightNavBarEnabled; + default: + return false; + } + } + + protected boolean getHideForKeyboardBySide(@SystemBarSide int side) { + return mSystemBarConfigMap.get(side) != null + && mSystemBarConfigMap.get(side).getHideForKeyboard(); + } + + protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) { + int[] paddings = mSystemBarConfigMap.get(side).getPaddings(); + view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]); + } + + protected List getSystemBarSidesByZOrder() { + return mSystemBarSidesByZOrder; + } + + @VisibleForTesting + protected static int getHunZOrder() { + return HUN_ZORDER; + } + + private static void populateMaps() { + BAR_GRAVITY_MAP.put(TOP, Gravity.TOP); + BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM); + BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT); + BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT); + + BAR_TITLE_MAP.put(TOP, "TopCarSystemBar"); + BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar"); + BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar"); + BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar"); + + BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_MANDATORY_GESTURES); + BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES); + BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_MANDATORY_GESTURES); + BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_MANDATORY_GESTURES); + } + + private void readConfigs() { + mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopNavigationBar); + mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomNavigationBar); + mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftNavigationBar); + mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightNavigationBar); + + if (mTopNavBarEnabled) { + SystemBarConfig topBarConfig = + new SystemBarConfigBuilder() + .setSide(TOP) + .setGirth(mResources.getDimensionPixelSize( + R.dimen.car_top_navigation_bar_height)) + .setBarType(mResources.getInteger(R.integer.config_topSystemBarType)) + .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder)) + .setHideForKeyboard(mResources.getBoolean( + R.bool.config_hideTopSystemBarForKeyboard)) + .build(); + mSystemBarConfigMap.put(TOP, topBarConfig); + } + + if (mBottomNavBarEnabled) { + SystemBarConfig bottomBarConfig = + new SystemBarConfigBuilder() + .setSide(BOTTOM) + .setGirth(mResources.getDimensionPixelSize( + R.dimen.car_bottom_navigation_bar_height)) + .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType)) + .setZOrder( + mResources.getInteger(R.integer.config_bottomSystemBarZOrder)) + .setHideForKeyboard(mResources.getBoolean( + R.bool.config_hideBottomSystemBarForKeyboard)) + .build(); + mSystemBarConfigMap.put(BOTTOM, bottomBarConfig); + } + + if (mLeftNavBarEnabled) { + SystemBarConfig leftBarConfig = + new SystemBarConfigBuilder() + .setSide(LEFT) + .setGirth(mResources.getDimensionPixelSize( + R.dimen.car_left_navigation_bar_width)) + .setBarType(mResources.getInteger(R.integer.config_leftSystemBarType)) + .setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder)) + .setHideForKeyboard(mResources.getBoolean( + R.bool.config_hideLeftSystemBarForKeyboard)) + .build(); + mSystemBarConfigMap.put(LEFT, leftBarConfig); + } + + if (mRightNavBarEnabled) { + SystemBarConfig rightBarConfig = + new SystemBarConfigBuilder() + .setSide(RIGHT) + .setGirth(mResources.getDimensionPixelSize( + R.dimen.car_right_navigation_bar_width)) + .setBarType(mResources.getInteger(R.integer.config_rightSystemBarType)) + .setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder)) + .setHideForKeyboard(mResources.getBoolean( + R.bool.config_hideRightSystemBarForKeyboard)) + .build(); + mSystemBarConfigMap.put(RIGHT, rightBarConfig); + } + } + + private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException { + Set barTypesUsed = new ArraySet<>(); + int enabledNavBarCount = mSystemBarConfigMap.size(); + + for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) { + barTypesUsed.add(systemBarConfig.getBarType()); + } + + // The number of bar types used cannot be fewer than that of enabled system bars. + if (barTypesUsed.size() < enabledNavBarCount) { + throw new RuntimeException("Each enabled system bar must have a unique bar type. Check " + + "the configuration in config.xml"); + } + } + + private void checkSystemBarEnabledForNotificationPanel() throws RuntimeException { + + String notificationPanelMediatorName = + mResources.getString(R.string.config_notificationPanelViewMediator); + if (notificationPanelMediatorName == null) { + return; + } + + Class notificationPanelMediatorUsed = null; + try { + notificationPanelMediatorUsed = Class.forName(notificationPanelMediatorName); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + if (!mTopNavBarEnabled && TopNotificationPanelViewMediator.class.isAssignableFrom( + notificationPanelMediatorUsed)) { + throw new RuntimeException( + "Top System Bar must be enabled to use " + notificationPanelMediatorName); + } + + if (!mBottomNavBarEnabled && BottomNotificationPanelViewMediator.class.isAssignableFrom( + notificationPanelMediatorUsed)) { + throw new RuntimeException("Bottom System Bar must be enabled to use " + + notificationPanelMediatorName); + } + } + + private void checkHideBottomBarForKeyboardConfigSync() throws RuntimeException { + if (mBottomNavBarEnabled) { + boolean actual = mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard); + boolean expected = mResources.getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard); + + if (actual != expected) { + throw new RuntimeException("config_hideBottomSystemBarForKeyboard must not be " + + "overlaid directly and should always refer to" + + "config_automotiveHideNavBarForKeyboard. However, their values " + + "currently do not sync. Set config_hideBottomSystemBarForKeyguard to " + + "@*android:bool/config_automotiveHideNavBarForKeyboard. To change its " + + "value, overlay config_automotiveHideNavBarForKeyboard in " + + "framework/base/core/res/res."); + } + } + } + + private void setInsetPaddingsForOverlappingCorners() { + setInsetPaddingForOverlappingCorner(TOP, LEFT); + setInsetPaddingForOverlappingCorner(TOP, RIGHT); + setInsetPaddingForOverlappingCorner(BOTTOM, LEFT); + setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT); + } + + private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide, + @SystemBarSide int verticalSide) { + + if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) { + Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and " + + "vertical sides were not provided correctly."); + return; + } + + SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide); + SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide); + + if (verticalBarConfig != null && horizontalBarConfig != null) { + int horizontalBarZOrder = horizontalBarConfig.getZOrder(); + int horizontalBarGirth = horizontalBarConfig.getGirth(); + int verticalBarZOrder = verticalBarConfig.getZOrder(); + int verticalBarGirth = verticalBarConfig.getGirth(); + + if (horizontalBarZOrder > verticalBarZOrder) { + verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth); + } else if (horizontalBarZOrder < verticalBarZOrder) { + horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth); + } else { + throw new RuntimeException( + BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide) + + " have the same Z-Order, and so their placing order cannot be " + + "determined. Determine which bar should be placed on top of the " + + "other bar and change the Z-order in config.xml accordingly." + ); + } + } + } + + private void sortSystemBarSidesByZOrder() { + List systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values()); + + systemBarsByZOrder.sort(new Comparator() { + @Override + public int compare(SystemBarConfig o1, SystemBarConfig o2) { + return o1.getZOrder() - o2.getZOrder(); + } + }); + + systemBarsByZOrder.forEach(systemBarConfig -> { + mSystemBarSidesByZOrder.add(systemBarConfig.getSide()); + }); + } + + private static boolean isHorizontalBar(@SystemBarSide int side) { + return side == TOP || side == BOTTOM; + } + + private static boolean isVerticalBar(@SystemBarSide int side) { + return side == LEFT || side == RIGHT; + } + + private static final class SystemBarConfig { + private final int mSide; + private final int mBarType; + private final int mGirth; + private final int mZOrder; + private final boolean mHideForKeyboard; + + private int[] mPaddings = new int[]{0, 0, 0, 0}; + + private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder, + boolean hideForKeyboard) { + mSide = side; + mBarType = barType; + mGirth = girth; + mZOrder = zOrder; + mHideForKeyboard = hideForKeyboard; + } + + private int getSide() { + return mSide; + } + + private int getBarType() { + return mBarType; + } + + private int getGirth() { + return mGirth; + } + + private int getZOrder() { + return mZOrder; + } + + private boolean getHideForKeyboard() { + return mHideForKeyboard; + } + + private int[] getPaddings() { + return mPaddings; + } + + private WindowManager.LayoutParams getLayoutParams() { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth, + isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT, + mapZOrderToBarType(mZOrder), + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + lp.setTitle(BAR_TITLE_MAP.get(mSide)); + lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)}; + lp.setFitInsetsTypes(0); + lp.windowAnimations = 0; + lp.gravity = BAR_GRAVITY_MAP.get(mSide); + return lp; + } + + private int mapZOrderToBarType(int zOrder) { + return zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL + : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; + } + + private void setPaddingBySide(@SystemBarSide int side, int padding) { + mPaddings[side] = padding; + } + } + + private static final class SystemBarConfigBuilder { + private int mSide; + private int mBarType; + private int mGirth; + private int mZOrder; + private boolean mHideForKeyboard; + + private SystemBarConfigBuilder setSide(@SystemBarSide int side) { + mSide = side; + return this; + } + + private SystemBarConfigBuilder setBarType(int type) { + mBarType = type; + return this; + } + + private SystemBarConfigBuilder setGirth(int girth) { + mGirth = girth; + return this; + } + + private SystemBarConfigBuilder setZOrder(int zOrder) { + mZOrder = zOrder; + return this; + } + + private SystemBarConfigBuilder setHideForKeyboard(boolean hide) { + mHideForKeyboard = hide; + return this; + } + + private SystemBarConfig build() { + return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder, mHideForKeyboard); + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index 1eead62c042a343a9ba107f6b2d73a5fc1129e62..fd804c71c9d0a17a06dfe76d8094bd7a154f08f4 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -23,6 +23,8 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.inputmethodservice.InputMethodService; +import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.view.GestureDetector; @@ -80,6 +82,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController private final StatusBarStateController mStatusBarStateController; private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; private final NotificationVisibilityLogger mNotificationVisibilityLogger; + private final int mNavBarHeight; private float mInitialBackgroundAlpha; private float mBackgroundAlphaDiff; @@ -89,7 +92,6 @@ public class NotificationPanelViewController extends OverlayPanelViewController private RecyclerView mNotificationList; private NotificationViewController mNotificationViewController; - private boolean mIsTracking; private boolean mNotificationListAtEnd; private float mFirstTouchDownOnGlassPane; private boolean mNotificationListAtEndAtTimeOfTouch; @@ -137,7 +139,10 @@ public class NotificationPanelViewController extends OverlayPanelViewController mStatusBarStateController = statusBarStateController; mNotificationVisibilityLogger = notificationVisibilityLogger; + mNavBarHeight = mResources.getDimensionPixelSize(R.dimen.car_bottom_navigation_bar_height); + mCommandQueue.addCallback(this); + // Notification background setup. mInitialBackgroundAlpha = (float) mResources.getInteger( R.integer.config_initialNotificationBackgroundAlpha) / 100; @@ -178,6 +183,27 @@ public class NotificationPanelViewController extends OverlayPanelViewController } } + @Override + public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, + boolean showImeSwitcher) { + if (mContext.getDisplayId() != displayId) { + return; + } + boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; + int bottomMargin = isKeyboardVisible ? 0 : mNavBarHeight; + ViewGroup container = (ViewGroup) getLayout(); + if (container == null) { + // Notification panel hasn't been inflated before. We shouldn't try to update the layout + // params. + return; + } + + ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) container.getLayoutParams(); + params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin); + container.setLayoutParams(params); + } + // OverlayViewController @Override @@ -192,10 +218,20 @@ public class NotificationPanelViewController extends OverlayPanelViewController } @Override - protected boolean shouldShowNavigationBar() { + protected boolean shouldShowNavigationBarInsets() { + return true; + } + + @Override + protected boolean shouldShowStatusBarInsets() { return true; } + @Override + protected int getInsetTypesToFit() { + return 0; + } + @Override protected boolean shouldShowHUN() { return mEnableHeadsUpNotificationWhenNotificationShadeOpen; @@ -287,14 +323,14 @@ public class NotificationPanelViewController extends OverlayPanelViewController // The glass pane is used to view touch events before passed to the notification list. // This allows us to initialize gesture listeners and detect when to close the notifications glassPane.setOnTouchListener((v, event) -> { - if (event.getActionMasked() == MotionEvent.ACTION_UP) { + if (isClosingAction(event)) { mNotificationListAtEndAtTimeOfTouch = false; } - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (isOpeningAction(event)) { mFirstTouchDownOnGlassPane = event.getRawX(); mNotificationListAtEndAtTimeOfTouch = mNotificationListAtEnd; // Reset the tracker when there is a touch down on the glass pane. - mIsTracking = false; + setIsTracking(false); // Pass the down event to gesture detector so that it knows where the touch event // started. closeGestureDetector.onTouchEvent(event); @@ -329,22 +365,21 @@ public class NotificationPanelViewController extends OverlayPanelViewController // If the card is swiping we should not allow the notification shade to close. // Hence setting mNotificationListAtEndAtTimeOfTouch to false will stop that - // for us. We are also checking for mIsTracking because while swiping the + // for us. We are also checking for isTracking() because while swiping the // notification shade to close if the user goes a bit horizontal while swiping // upwards then also this should close. - if (mIsNotificationCardSwiping && !mIsTracking) { + if (mIsNotificationCardSwiping && !isTracking()) { mNotificationListAtEndAtTimeOfTouch = false; } boolean handled = closeGestureDetector.onTouchEvent(event); - boolean isTracking = mIsTracking; + boolean isTracking = isTracking(); Rect rect = getLayout().getClipBounds(); float clippedHeight = 0; if (rect != null) { clippedHeight = rect.bottom; } - if (!handled && event.getActionMasked() == MotionEvent.ACTION_UP - && mIsSwipingVerticallyToClose) { + if (!handled && isClosingAction(event) && mIsSwipingVerticallyToClose) { if (getSettleClosePercentage() < getPercentageFromEndingEdge() && isTracking) { animatePanel(DEFAULT_FLING_VELOCITY, false); } else if (clippedHeight != getLayout().getHeight() && isTracking) { @@ -357,7 +392,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController // Updating the mNotificationListAtEndAtTimeOfTouch state has to be done after // the event has been passed to the closeGestureDetector above, such that the // closeGestureDetector sees the up event before the state has changed. - if (event.getActionMasked() == MotionEvent.ACTION_UP) { + if (isClosingAction(event)) { mNotificationListAtEndAtTimeOfTouch = false; } return handled || isTracking; diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java deleted file mode 100644 index d692487d410ea373b80cba4b0c00549a2cba11db..0000000000000000000000000000000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.statusbar; - -import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME; - -import android.annotation.Nullable; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.PowerManager; -import android.util.DisplayMetrics; -import android.util.Log; -import android.view.View; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.statusbar.RegisterStatusBarResult; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.BatteryMeterView; -import com.android.systemui.Dependency; -import com.android.systemui.InitController; -import com.android.systemui.Prefs; -import com.android.systemui.R; -import com.android.systemui.assist.AssistManager; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.car.CarDeviceProvisionedController; -import com.android.systemui.car.CarDeviceProvisionedListener; -import com.android.systemui.car.bluetooth.CarBatteryController; -import com.android.systemui.car.navigationbar.CarNavigationBarController; -import com.android.systemui.classifier.FalsingLog; -import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.UiBackground; -import com.android.systemui.fragments.FragmentHostManager; -import com.android.systemui.keyguard.DismissCallbackRegistry; -import com.android.systemui.keyguard.KeyguardViewMediator; -import com.android.systemui.keyguard.ScreenLifecycle; -import com.android.systemui.keyguard.WakefulnessLifecycle; -import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.plugins.PluginDependencyProvider; -import com.android.systemui.plugins.qs.QS; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.ScreenPinningRequest; -import com.android.systemui.shared.plugins.PluginManager; -import com.android.systemui.stackdivider.Divider; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.KeyguardIndicationController; -import com.android.systemui.statusbar.NavigationBarController; -import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.NotificationShadeDepthController; -import com.android.systemui.statusbar.NotificationViewHierarchyManager; -import com.android.systemui.statusbar.PulseExpansionHandler; -import com.android.systemui.statusbar.SuperStatusBarViewFactory; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.init.NotificationsController; -import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; -import com.android.systemui.statusbar.notification.logging.NotificationLogger; -import com.android.systemui.statusbar.notification.row.NotificationGutsManager; -import com.android.systemui.statusbar.phone.AutoHideController; -import com.android.systemui.statusbar.phone.BiometricUnlockController; -import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; -import com.android.systemui.statusbar.phone.DozeParameters; -import com.android.systemui.statusbar.phone.DozeScrimController; -import com.android.systemui.statusbar.phone.DozeServiceHost; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; -import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.KeyguardDismissUtil; -import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.statusbar.phone.LightsOutNotifController; -import com.android.systemui.statusbar.phone.LockscreenLockIconController; -import com.android.systemui.statusbar.phone.LockscreenWallpaper; -import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; -import com.android.systemui.statusbar.phone.ScrimController; -import com.android.systemui.statusbar.phone.ShadeController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.phone.StatusBarIconController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; -import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; -import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; -import com.android.systemui.statusbar.policy.BatteryController; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.ExtensionController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.NetworkController; -import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; -import com.android.systemui.statusbar.policy.UserInfoControllerImpl; -import com.android.systemui.statusbar.policy.UserSwitcherController; -import com.android.systemui.volume.VolumeComponent; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.Executor; - -import javax.inject.Named; -import javax.inject.Provider; - -import dagger.Lazy; - -/** - * A status bar tailored for the automotive use case. - */ -public class CarStatusBar extends StatusBar implements CarBatteryController.BatteryViewHandler { - private static final String TAG = "CarStatusBar"; - - private final UserSwitcherController mUserSwitcherController; - private final ScrimController mScrimController; - - private CarBatteryController mCarBatteryController; - private BatteryMeterView mBatteryMeterView; - private Drawable mNotificationPanelBackground; - - private final Object mQueueLock = new Object(); - private final CarNavigationBarController mCarNavigationBarController; - private final CarDeviceProvisionedController mCarDeviceProvisionedController; - private final ScreenLifecycle mScreenLifecycle; - - private boolean mDeviceIsSetUpForUser = true; - private boolean mIsUserSetupInProgress = false; - - public CarStatusBar( - Context context, - NotificationsController notificationsController, - LightBarController lightBarController, - AutoHideController autoHideController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - StatusBarIconController statusBarIconController, - PulseExpansionHandler pulseExpansionHandler, - NotificationWakeUpCoordinator notificationWakeUpCoordinator, - KeyguardBypassController keyguardBypassController, - KeyguardStateController keyguardStateController, - HeadsUpManagerPhone headsUpManagerPhone, - DynamicPrivacyController dynamicPrivacyController, - BypassHeadsUpNotifier bypassHeadsUpNotifier, - FalsingManager falsingManager, - BroadcastDispatcher broadcastDispatcher, - RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, - NotificationGutsManager notificationGutsManager, - NotificationLogger notificationLogger, - NotificationInterruptStateProvider notificationInterruptStateProvider, - NotificationViewHierarchyManager notificationViewHierarchyManager, - KeyguardViewMediator keyguardViewMediator, - DisplayMetrics displayMetrics, - MetricsLogger metricsLogger, - @UiBackground Executor uiBgExecutor, - NotificationMediaManager notificationMediaManager, - NotificationLockscreenUserManager lockScreenUserManager, - NotificationRemoteInputManager remoteInputManager, - UserSwitcherController userSwitcherController, - NetworkController networkController, - BatteryController batteryController, - SysuiColorExtractor colorExtractor, - ScreenLifecycle screenLifecycle, - WakefulnessLifecycle wakefulnessLifecycle, - SysuiStatusBarStateController statusBarStateController, - VibratorHelper vibratorHelper, - BubbleController bubbleController, - NotificationGroupManager groupManager, - VisualStabilityManager visualStabilityManager, - CarDeviceProvisionedController carDeviceProvisionedController, - NavigationBarController navigationBarController, - Lazy assistManagerLazy, - ConfigurationController configurationController, - NotificationShadeWindowController notificationShadeWindowController, - LockscreenLockIconController lockscreenLockIconController, - DozeParameters dozeParameters, - ScrimController scrimController, - Lazy lockscreenWallpaperLazy, - Lazy biometricUnlockControllerLazy, - DozeServiceHost dozeServiceHost, - PowerManager powerManager, - ScreenPinningRequest screenPinningRequest, - DozeScrimController dozeScrimController, - VolumeComponent volumeComponent, - CommandQueue commandQueue, - Optional recents, - Provider statusBarComponentBuilder, - PluginManager pluginManager, - Optional dividerOptional, - SuperStatusBarViewFactory superStatusBarViewFactory, - LightsOutNotifController lightsOutNotifController, - StatusBarNotificationActivityStarter.Builder - statusBarNotificationActivityStarterBuilder, - ShadeController shadeController, - StatusBarKeyguardViewManager statusBarKeyguardViewManager, - ViewMediatorCallback viewMediatorCallback, - InitController initController, - DarkIconDispatcher darkIconDispatcher, - @Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler, - PluginDependencyProvider pluginDependencyProvider, - KeyguardDismissUtil keyguardDismissUtil, - ExtensionController extensionController, - UserInfoControllerImpl userInfoControllerImpl, - PhoneStatusBarPolicy phoneStatusBarPolicy, - KeyguardIndicationController keyguardIndicationController, - DismissCallbackRegistry dismissCallbackRegistry, - StatusBarTouchableRegionManager statusBarTouchableRegionManager, - Lazy depthControllerLazy, - /* Car Settings injected components. */ - CarNavigationBarController carNavigationBarController) { - super( - context, - notificationsController, - lightBarController, - autoHideController, - keyguardUpdateMonitor, - statusBarIconController, - pulseExpansionHandler, - notificationWakeUpCoordinator, - keyguardBypassController, - keyguardStateController, - headsUpManagerPhone, - dynamicPrivacyController, - bypassHeadsUpNotifier, - falsingManager, - broadcastDispatcher, - remoteInputQuickSettingsDisabler, - notificationGutsManager, - notificationLogger, - notificationInterruptStateProvider, - notificationViewHierarchyManager, - keyguardViewMediator, - displayMetrics, - metricsLogger, - uiBgExecutor, - notificationMediaManager, - lockScreenUserManager, - remoteInputManager, - userSwitcherController, - networkController, - batteryController, - colorExtractor, - screenLifecycle, - wakefulnessLifecycle, - statusBarStateController, - vibratorHelper, - bubbleController, - groupManager, - visualStabilityManager, - carDeviceProvisionedController, - navigationBarController, - assistManagerLazy, - configurationController, - notificationShadeWindowController, - lockscreenLockIconController, - dozeParameters, - scrimController, - null /* keyguardLiftController */, - lockscreenWallpaperLazy, - biometricUnlockControllerLazy, - dozeServiceHost, - powerManager, - screenPinningRequest, - dozeScrimController, - volumeComponent, - commandQueue, - recents, - statusBarComponentBuilder, - pluginManager, - dividerOptional, - lightsOutNotifController, - statusBarNotificationActivityStarterBuilder, - shadeController, - superStatusBarViewFactory, - statusBarKeyguardViewManager, - viewMediatorCallback, - initController, - darkIconDispatcher, - timeTickHandler, - pluginDependencyProvider, - keyguardDismissUtil, - extensionController, - userInfoControllerImpl, - phoneStatusBarPolicy, - keyguardIndicationController, - dismissCallbackRegistry, - depthControllerLazy, - statusBarTouchableRegionManager); - mUserSwitcherController = userSwitcherController; - mScrimController = scrimController; - mCarDeviceProvisionedController = carDeviceProvisionedController; - mCarNavigationBarController = carNavigationBarController; - mScreenLifecycle = screenLifecycle; - } - - @Override - public void start() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController.isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController.isCurrentUserSetupInProgress(); - - super.start(); - - createBatteryController(); - mCarBatteryController.startListening(); - - mCarDeviceProvisionedController.addCallback( - new CarDeviceProvisionedListener() { - @Override - public void onUserSetupInProgressChanged() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - - @Override - public void onUserSetupChanged() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - - @Override - public void onUserSwitched() { - mDeviceIsSetUpForUser = mCarDeviceProvisionedController - .isCurrentUserSetup(); - mIsUserSetupInProgress = mCarDeviceProvisionedController - .isCurrentUserSetupInProgress(); - } - }); - - mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() { - @Override - public String getName() { - return TAG; - } - - @Override - public boolean suppressInterruptions(NotificationEntry entry) { - // Because space is usually constrained in the auto use-case, there should not be a - // pinned notification when the shade has been expanded. - // Ensure this by not allowing any interruptions (ie: pinning any notifications) if - // the shade is already opened. - return !getPresenter().isPresenterFullyCollapsed(); - } - }); - } - - @Override - public boolean hideKeyguard() { - boolean result = super.hideKeyguard(); - mCarNavigationBarController.hideAllKeyguardButtons(isDeviceSetupForUser()); - return result; - } - - @Override - public void showKeyguard() { - super.showKeyguard(); - mCarNavigationBarController.showAllKeyguardButtons(isDeviceSetupForUser()); - } - - private boolean isDeviceSetupForUser() { - return mDeviceIsSetUpForUser && !mIsUserSetupInProgress; - } - - @Override - protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) { - super.makeStatusBarView(result); - - mNotificationPanelBackground = getDefaultWallpaper(); - mScrimController.setScrimBehindDrawable(mNotificationPanelBackground); - - FragmentHostManager manager = FragmentHostManager.get(mPhoneStatusBarWindow); - manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { - mBatteryMeterView = fragment.getView().findViewById(R.id.battery); - - // By default, the BatteryMeterView should not be visible. It will be toggled - // when a device has connected by bluetooth. - mBatteryMeterView.setVisibility(View.GONE); - }); - } - - @Override - public void animateExpandNotificationsPanel() { - // No op. - } - - @Override - protected QS createDefaultQSFragment() { - return null; - } - - private BatteryController createBatteryController() { - mCarBatteryController = new CarBatteryController(mContext); - mCarBatteryController.addBatteryViewHandler(this); - return mCarBatteryController; - } - - @Override - protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { - // No op. - } - - @Override - public void notifyBiometricAuthModeChanged() { - // No op. - } - - @Override - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - //When executing dump() function simultaneously, we need to serialize them - //to get mStackScroller's position correctly. - synchronized (mQueueLock) { - pw.println(" mStackScroller: " + viewInfo(mStackScroller)); - pw.println(" mStackScroller: " + viewInfo(mStackScroller) - + " scroll " + mStackScroller.getScrollX() - + "," + mStackScroller.getScrollY()); - } - pw.print(" mCarBatteryController="); - pw.println(mCarBatteryController); - pw.print(" mBatteryMeterView="); - pw.println(mBatteryMeterView); - - if (Dependency.get(KeyguardUpdateMonitor.class) != null) { - Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args); - } - - FalsingLog.dump(pw); - - pw.println("SharedPreferences:"); - for (Map.Entry entry : Prefs.getAll(mContext).entrySet()) { - pw.print(" "); - pw.print(entry.getKey()); - pw.print("="); - pw.println(entry.getValue()); - } - } - - @Override - public void showBatteryView() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView); - } - - if (mBatteryMeterView != null) { - mBatteryMeterView.setVisibility(View.VISIBLE); - } - } - - @Override - public void hideBatteryView() { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "hideBatteryView(). mBatteryMeterView: " + mBatteryMeterView); - } - - if (mBatteryMeterView != null) { - mBatteryMeterView.setVisibility(View.GONE); - } - } - - @Override - protected void createUserSwitcher() { - if (!mUserSwitcherController.useFullscreenUserSwitcher()) { - super.createUserSwitcher(); - } - } - - /** - * Dismisses the keyguard and shows bouncer if authentication is necessary. - */ - public void dismissKeyguard() { - // Don't dismiss keyguard when the screen is off. - if (mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF) { - return; - } - executeRunnableDismissingKeyguard(null/* runnable */, null /* cancelAction */, - true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); - } - - /** - * Ensures that relevant child views are appropriately recreated when the device's density - * changes. - */ - @Override - public void onDensityOrFontScaleChanged() { - super.onDensityOrFontScaleChanged(); - // Need to update the background on density changed in case the change was due to night - // mode. - mNotificationPanelBackground = getDefaultWallpaper(); - mScrimController.setScrimBehindDrawable(mNotificationPanelBackground); - } - - /** - * Returns the {@link Drawable} that represents the wallpaper that the user has currently set. - */ - private Drawable getDefaultWallpaper() { - return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java deleted file mode 100644 index 96a998a500e1ec28e8c5c6db7126937c853d545c..0000000000000000000000000000000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarKeyguardViewManager.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.car.statusbar; - -import android.content.Context; -import android.view.View; - -import com.android.internal.widget.LockPatternUtils; -import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.keyguard.ViewMediatorCallback; -import com.android.systemui.R; -import com.android.systemui.car.navigationbar.CarNavigationBarController; -import com.android.systemui.dock.DockManager; -import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.SysuiStatusBarStateController; -import com.android.systemui.statusbar.phone.NavigationModeController; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.KeyguardStateController; - -import java.util.HashSet; -import java.util.Set; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Car implementation of the {@link StatusBarKeyguardViewManager}. */ -@Singleton -public class CarStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { - - protected boolean mShouldHideNavBar; - private final CarNavigationBarController mCarNavigationBarController; - private Set mKeygaurdCancelClickedListenerSet; - - @Inject - public CarStatusBarKeyguardViewManager(Context context, - ViewMediatorCallback callback, - LockPatternUtils lockPatternUtils, - SysuiStatusBarStateController sysuiStatusBarStateController, - ConfigurationController configurationController, - KeyguardUpdateMonitor keyguardUpdateMonitor, - NavigationModeController navigationModeController, - DockManager dockManager, - NotificationShadeWindowController notificationShadeWindowController, - KeyguardStateController keyguardStateController, - NotificationMediaManager notificationMediaManager, - CarNavigationBarController carNavigationBarController) { - super(context, callback, lockPatternUtils, sysuiStatusBarStateController, - configurationController, keyguardUpdateMonitor, navigationModeController, - dockManager, notificationShadeWindowController, keyguardStateController, - notificationMediaManager); - mShouldHideNavBar = context.getResources() - .getBoolean(R.bool.config_hideNavWhenKeyguardBouncerShown); - mCarNavigationBarController = carNavigationBarController; - mKeygaurdCancelClickedListenerSet = new HashSet<>(); - } - - @Override - protected void updateNavigationBarVisibility(boolean navBarVisible) { - if (!mShouldHideNavBar) { - return; - } - int visibility = navBarVisible ? View.VISIBLE : View.GONE; - mCarNavigationBarController.setBottomWindowVisibility(visibility); - mCarNavigationBarController.setLeftWindowVisibility(visibility); - mCarNavigationBarController.setRightWindowVisibility(visibility); - } - - /** - * Car is a multi-user system. There's a cancel button on the bouncer that allows the user to - * go back to the user switcher and select another user. Different user may have different - * security mode which requires bouncer container to be resized. For this reason, the bouncer - * view is destroyed on cancel. - */ - @Override - protected boolean shouldDestroyViewOnReset() { - return true; - } - - /** - * Called when cancel button in bouncer is pressed. - */ - @Override - public void onCancelClicked() { - mKeygaurdCancelClickedListenerSet.forEach(OnKeyguardCancelClickedListener::onCancelClicked); - } - - /** - * Do nothing on this change. - * The base class hides the keyguard which for automotive we want to avoid b/c this would happen - * on a configuration change due to day/night (headlight state). - */ - @Override - public void onDensityOrFontScaleChanged() { } - - /** - * Add listener for keyguard cancel clicked. - */ - public void addOnKeyguardCancelClickedListener( - OnKeyguardCancelClickedListener keyguardCancelClickedListener) { - mKeygaurdCancelClickedListenerSet.add(keyguardCancelClickedListener); - } - - /** - * Remove listener for keyguard cancel clicked. - */ - public void removeOnKeyguardCancelClickedListener( - OnKeyguardCancelClickedListener keyguardCancelClickedListener) { - mKeygaurdCancelClickedListenerSet.remove(keyguardCancelClickedListener); - } - - - /** - * Defines a callback for keyguard cancel button clicked listeners. - */ - public interface OnKeyguardCancelClickedListener { - /** - * Called when keyguard cancel button is clicked. - */ - void onCancelClicked(); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBar.java new file mode 100644 index 0000000000000000000000000000000000000000..48334bd6e5c7bc1395e78498b7081d5b77db91f7 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBar.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.car.statusbar; + +import android.content.Context; +import android.os.Handler; +import android.os.PowerManager; +import android.util.DisplayMetrics; + +import com.android.internal.logging.MetricsLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.InitController; +import com.android.systemui.assist.AssistManager; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.bubbles.BubbleController; +import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.keyguard.KeyguardViewMediator; +import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.plugins.DarkIconDispatcher; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.PluginDependencyProvider; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.ScreenPinningRequest; +import com.android.systemui.shared.plugins.PluginManager; +import com.android.systemui.stackdivider.Divider; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.KeyguardIndicationController; +import com.android.systemui.statusbar.NavigationBarController; +import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationMediaManager; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.NotificationShadeDepthController; +import com.android.systemui.statusbar.NotificationViewHierarchyManager; +import com.android.systemui.statusbar.PulseExpansionHandler; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; +import com.android.systemui.statusbar.SysuiStatusBarStateController; +import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.notification.DynamicPrivacyController; +import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.init.NotificationsController; +import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; +import com.android.systemui.statusbar.notification.logging.NotificationLogger; +import com.android.systemui.statusbar.notification.row.NotificationGutsManager; +import com.android.systemui.statusbar.phone.AutoHideController; +import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.DozeParameters; +import com.android.systemui.statusbar.phone.DozeScrimController; +import com.android.systemui.statusbar.phone.DozeServiceHost; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.KeyguardDismissUtil; +import com.android.systemui.statusbar.phone.KeyguardLiftController; +import com.android.systemui.statusbar.phone.LightBarController; +import com.android.systemui.statusbar.phone.LightsOutNotifController; +import com.android.systemui.statusbar.phone.LockscreenLockIconController; +import com.android.systemui.statusbar.phone.LockscreenWallpaper; +import com.android.systemui.statusbar.phone.NavigationBarView; +import com.android.systemui.statusbar.phone.NotificationGroupManager; +import com.android.systemui.statusbar.phone.NotificationShadeWindowController; +import com.android.systemui.statusbar.phone.PhoneStatusBarPolicy; +import com.android.systemui.statusbar.phone.ScrimController; +import com.android.systemui.statusbar.phone.ShadeController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; +import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter; +import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; +import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.ExtensionController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; +import com.android.systemui.statusbar.policy.UserInfoControllerImpl; +import com.android.systemui.statusbar.policy.UserSwitcherController; +import com.android.systemui.volume.VolumeComponent; + +import java.util.Optional; +import java.util.concurrent.Executor; + +import javax.inject.Provider; + +import dagger.Lazy; + +/** Unused variant of {@link StatusBar} specifically used in the automotive context. */ +public class UnusedStatusBar extends StatusBar { + + public UnusedStatusBar(Context context, + NotificationsController notificationsController, + LightBarController lightBarController, + AutoHideController autoHideController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + StatusBarIconController statusBarIconController, + PulseExpansionHandler pulseExpansionHandler, + NotificationWakeUpCoordinator notificationWakeUpCoordinator, + KeyguardBypassController keyguardBypassController, + KeyguardStateController keyguardStateController, + HeadsUpManagerPhone headsUpManagerPhone, + DynamicPrivacyController dynamicPrivacyController, + BypassHeadsUpNotifier bypassHeadsUpNotifier, + FalsingManager falsingManager, + BroadcastDispatcher broadcastDispatcher, + RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, + NotificationGutsManager notificationGutsManager, + NotificationLogger notificationLogger, + NotificationInterruptStateProvider notificationInterruptStateProvider, + NotificationViewHierarchyManager notificationViewHierarchyManager, + KeyguardViewMediator keyguardViewMediator, + DisplayMetrics displayMetrics, + MetricsLogger metricsLogger, + Executor uiBgExecutor, + NotificationMediaManager notificationMediaManager, + NotificationLockscreenUserManager lockScreenUserManager, + NotificationRemoteInputManager remoteInputManager, + UserSwitcherController userSwitcherController, + NetworkController networkController, + BatteryController batteryController, + SysuiColorExtractor colorExtractor, + ScreenLifecycle screenLifecycle, + WakefulnessLifecycle wakefulnessLifecycle, + SysuiStatusBarStateController statusBarStateController, + VibratorHelper vibratorHelper, + BubbleController bubbleController, + NotificationGroupManager groupManager, + VisualStabilityManager visualStabilityManager, + DeviceProvisionedController deviceProvisionedController, + NavigationBarController navigationBarController, + Lazy assistManagerLazy, + ConfigurationController configurationController, + NotificationShadeWindowController notificationShadeWindowController, + LockscreenLockIconController lockscreenLockIconController, + DozeParameters dozeParameters, + ScrimController scrimController, + KeyguardLiftController keyguardLiftController, + Lazy lockscreenWallpaperLazy, + Lazy biometricUnlockControllerLazy, + DozeServiceHost dozeServiceHost, + PowerManager powerManager, + ScreenPinningRequest screenPinningRequest, + DozeScrimController dozeScrimController, + VolumeComponent volumeComponent, + CommandQueue commandQueue, + Optional recentsOptional, + Provider statusBarComponentBuilder, + PluginManager pluginManager, + Optional dividerOptional, + LightsOutNotifController lightsOutNotifController, + StatusBarNotificationActivityStarter.Builder statusBarNotifActivityStarterBuilder, + ShadeController shadeController, + SuperStatusBarViewFactory superStatusBarViewFactory, + StatusBarKeyguardViewManager statusBarKeyguardViewManager, + ViewMediatorCallback viewMediatorCallback, + InitController initController, + DarkIconDispatcher darkIconDispatcher, + Handler timeTickHandler, + PluginDependencyProvider pluginDependencyProvider, + KeyguardDismissUtil keyguardDismissUtil, + ExtensionController extensionController, + UserInfoControllerImpl userInfoControllerImpl, + PhoneStatusBarPolicy phoneStatusBarPolicy, + KeyguardIndicationController keyguardIndicationController, + DismissCallbackRegistry dismissCallbackRegistry, + Lazy notificationShadeDepthControllerLazy, + StatusBarTouchableRegionManager statusBarTouchableRegionManager) { + super(context, notificationsController, lightBarController, autoHideController, + keyguardUpdateMonitor, statusBarIconController, pulseExpansionHandler, + notificationWakeUpCoordinator, keyguardBypassController, keyguardStateController, + headsUpManagerPhone, dynamicPrivacyController, bypassHeadsUpNotifier, + falsingManager, + broadcastDispatcher, remoteInputQuickSettingsDisabler, notificationGutsManager, + notificationLogger, notificationInterruptStateProvider, + notificationViewHierarchyManager, keyguardViewMediator, displayMetrics, + metricsLogger, + uiBgExecutor, notificationMediaManager, lockScreenUserManager, remoteInputManager, + userSwitcherController, networkController, batteryController, colorExtractor, + screenLifecycle, wakefulnessLifecycle, statusBarStateController, vibratorHelper, + bubbleController, groupManager, visualStabilityManager, deviceProvisionedController, + navigationBarController, assistManagerLazy, configurationController, + notificationShadeWindowController, lockscreenLockIconController, dozeParameters, + scrimController, keyguardLiftController, lockscreenWallpaperLazy, + biometricUnlockControllerLazy, dozeServiceHost, powerManager, screenPinningRequest, + dozeScrimController, volumeComponent, commandQueue, recentsOptional, + statusBarComponentBuilder, pluginManager, dividerOptional, lightsOutNotifController, + statusBarNotifActivityStarterBuilder, shadeController, superStatusBarViewFactory, + statusBarKeyguardViewManager, viewMediatorCallback, initController, + darkIconDispatcher, + timeTickHandler, pluginDependencyProvider, keyguardDismissUtil, extensionController, + userInfoControllerImpl, phoneStatusBarPolicy, keyguardIndicationController, + dismissCallbackRegistry, notificationShadeDepthControllerLazy, + statusBarTouchableRegionManager); + } + + @Override + public void notifyBiometricAuthModeChanged() { + // No-op for Automotive devices. + } + + @Override + public NavigationBarView getNavigationBarView() { + // Return null for Automotive devices. + return null; + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBarModule.java similarity index 94% rename from packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java rename to packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBarModule.java index dc2eb04c2990f9d120d740ac5bec587b132091a5..2c86e4db3b82f9f8e8e6e99c775c6024ed62fff9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/UnusedStatusBarModule.java @@ -23,6 +23,8 @@ import android.os.Handler; import android.os.PowerManager; import android.util.DisplayMetrics; +import androidx.annotation.Nullable; + import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; @@ -30,8 +32,6 @@ import com.android.systemui.InitController; import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; -import com.android.systemui.car.CarDeviceProvisionedController; -import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.phone.DozeServiceHost; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; +import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.LightBarController; import com.android.systemui.statusbar.phone.LightsOutNotifController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; @@ -92,6 +93,7 @@ import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneDependenciesModule; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; @@ -112,17 +114,17 @@ import dagger.Module; import dagger.Provides; /** - * Dagger Module providing {@link CarStatusBar}. + * Dagger Module providing {@link UnusedStatusBar}. */ @Module(includes = {StatusBarDependenciesModule.class, StatusBarPhoneDependenciesModule.class, NotificationRowModule.class}) -public class CarStatusBarModule { +public interface UnusedStatusBarModule { /** * Provides our instance of StatusBar which is considered optional. */ @Provides @Singleton - static CarStatusBar provideStatusBar( + static UnusedStatusBar provideStatusBar( Context context, NotificationsController notificationsController, LightBarController lightBarController, @@ -141,7 +143,7 @@ public class CarStatusBarModule { RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationInterruptStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, DisplayMetrics displayMetrics, @@ -161,7 +163,7 @@ public class CarStatusBarModule { BubbleController bubbleController, NotificationGroupManager groupManager, VisualStabilityManager visualStabilityManager, - CarDeviceProvisionedController carDeviceProvisionedController, + DeviceProvisionedController deviceProvisionedController, NavigationBarController navigationBarController, Lazy assistManagerLazy, ConfigurationController configurationController, @@ -169,6 +171,7 @@ public class CarStatusBarModule { LockscreenLockIconController lockscreenLockIconController, DozeParameters dozeParameters, ScrimController scrimController, + @Nullable KeyguardLiftController keyguardLiftController, Lazy lockscreenWallpaperLazy, Lazy biometricUnlockControllerLazy, DozeServiceHost dozeServiceHost, @@ -181,11 +184,11 @@ public class CarStatusBarModule { Provider statusBarComponentBuilder, PluginManager pluginManager, Optional dividerOptional, - SuperStatusBarViewFactory superStatusBarViewFactory, LightsOutNotifController lightsOutNotifController, StatusBarNotificationActivityStarter.Builder statusBarNotificationActivityStarterBuilder, ShadeController shadeController, + SuperStatusBarViewFactory superStatusBarViewFactory, StatusBarKeyguardViewManager statusBarKeyguardViewManager, ViewMediatorCallback viewMediatorCallback, InitController initController, @@ -197,11 +200,10 @@ public class CarStatusBarModule { UserInfoControllerImpl userInfoControllerImpl, PhoneStatusBarPolicy phoneStatusBarPolicy, KeyguardIndicationController keyguardIndicationController, + Lazy notificationShadeDepthController, DismissCallbackRegistry dismissCallbackRegistry, - StatusBarTouchableRegionManager statusBarTouchableRegionManager, - Lazy notificationShadeDepthControllerLazy, - CarNavigationBarController carNavigationBarController) { - return new CarStatusBar( + StatusBarTouchableRegionManager statusBarTouchableRegionManager) { + return new UnusedStatusBar( context, notificationsController, lightBarController, @@ -220,7 +222,7 @@ public class CarStatusBarModule { remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationInterruptionStateProvider, + notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, displayMetrics, @@ -240,7 +242,7 @@ public class CarStatusBarModule { bubbleController, groupManager, visualStabilityManager, - carDeviceProvisionedController, + deviceProvisionedController, navigationBarController, assistManagerLazy, configurationController, @@ -248,6 +250,7 @@ public class CarStatusBarModule { lockscreenLockIconController, dozeParameters, scrimController, + keyguardLiftController, lockscreenWallpaperLazy, biometricUnlockControllerLazy, dozeServiceHost, @@ -260,10 +263,10 @@ public class CarStatusBarModule { statusBarComponentBuilder, pluginManager, dividerOptional, - superStatusBarViewFactory, lightsOutNotifController, statusBarNotificationActivityStarterBuilder, shadeController, + superStatusBarViewFactory, statusBarKeyguardViewManager, viewMediatorCallback, initController, @@ -276,8 +279,7 @@ public class CarStatusBarModule { phoneStatusBarPolicy, keyguardIndicationController, dismissCallbackRegistry, - statusBarTouchableRegionManager, - notificationShadeDepthControllerLazy, - carNavigationBarController); + notificationShadeDepthController, + statusBarTouchableRegionManager); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java index 10b2b973071a5d005d81c1fc66c005b1bcee202b..aac4cfbf83c41c34ef7d3b8ea53a96f1fd830969 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullScreenUserSwitcherViewController.java @@ -18,6 +18,8 @@ package com.android.systemui.car.userswitcher; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.car.Car; +import android.car.user.CarUserManager; import android.content.Context; import android.content.res.Resources; import android.view.View; @@ -25,6 +27,7 @@ import android.view.View; import androidx.recyclerview.widget.GridLayoutManager; import com.android.systemui.R; +import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.window.OverlayViewController; import com.android.systemui.car.window.OverlayViewGlobalStateController; import com.android.systemui.dagger.qualifiers.Main; @@ -39,7 +42,9 @@ import javax.inject.Singleton; public class FullScreenUserSwitcherViewController extends OverlayViewController { private final Context mContext; private final Resources mResources; + private final CarServiceProvider mCarServiceProvider; private final int mShortAnimationDuration; + private CarUserManager mCarUserManager; private UserGridRecyclerView mUserGridView; private UserGridRecyclerView.UserSelectionListener mUserSelectionListener; @@ -47,10 +52,16 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController public FullScreenUserSwitcherViewController( Context context, @Main Resources resources, + CarServiceProvider carServiceProvider, OverlayViewGlobalStateController overlayViewGlobalStateController) { super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController); mContext = context; mResources = resources; + mCarServiceProvider = carServiceProvider; + mCarServiceProvider.addListener(car -> { + mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE); + registerCarUserManagerIfPossible(); + }); mShortAnimationDuration = mResources.getInteger(android.R.integer.config_shortAnimTime); } @@ -63,6 +74,12 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserGridView.setUserSelectionListener(mUserSelectionListener); + registerCarUserManagerIfPossible(); + } + + @Override + protected boolean shouldFocusWindow() { + return false; } @Override @@ -90,18 +107,6 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController } - /** - * Invalidate underlying view. - */ - void invalidate() { - if (getLayout() == null) { - // layout hasn't been inflated. - return; - } - - getLayout().invalidate(); - } - /** * Set {@link UserGridRecyclerView.UserSelectionListener}. */ @@ -110,15 +115,9 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController mUserSelectionListener = userGridSelectionListener; } - /** - * Returns {@code true} when layout is visible. - */ - boolean isVisible() { - if (getLayout() == null) { - // layout hasn't been inflated. - return false; + private void registerCarUserManagerIfPossible() { + if (mUserGridView != null && mCarUserManager != null) { + mUserGridView.setCarUserManager(mCarUserManager); } - - return getLayout().getVisibility() == View.VISIBLE; } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java index a526e69430040d6ed6f71e8abef6a167bb3a4b36..a374df6fcaeeed01f9bba5f7905197a79481dec1 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java @@ -24,11 +24,15 @@ import static android.view.WindowInsets.Type.statusBars; import android.annotation.IntDef; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.Dialog; -import android.car.userlib.CarUserManagerHelper; +import android.car.user.CarUserManager; +import android.car.user.UserCreationResult; +import android.car.user.UserSwitchResult; +import android.car.userlib.UserHelper; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -40,7 +44,9 @@ import android.graphics.Rect; import android.os.AsyncTask; import android.os.UserHandle; import android.os.UserManager; +import android.sysprop.CarProperties; import android.util.AttributeSet; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -54,6 +60,7 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import com.android.internal.infra.AndroidFuture; import com.android.internal.util.UserIcons; import com.android.systemui.R; @@ -61,6 +68,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -68,9 +76,12 @@ import java.util.stream.Collectors; * One of the uses of this is for the lock screen in auto. */ public class UserGridRecyclerView extends RecyclerView { + private static final String TAG = UserGridRecyclerView.class.getSimpleName(); + private static final int TIMEOUT_MS = CarProperties.user_hal_timeout().orElse(5_000) + 500; + private UserSelectionListener mUserSelectionListener; private UserAdapter mAdapter; - private CarUserManagerHelper mCarUserManagerHelper; + private CarUserManager mCarUserManager; private UserManager mUserManager; private Context mContext; private UserIconProvider mUserIconProvider; @@ -85,7 +96,6 @@ public class UserGridRecyclerView extends RecyclerView { public UserGridRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; - mCarUserManagerHelper = new CarUserManagerHelper(mContext); mUserManager = UserManager.get(mContext); mUserIconProvider = new UserIconProvider(); @@ -184,6 +194,11 @@ public class UserGridRecyclerView extends RecyclerView { mUserSelectionListener = userSelectionListener; } + /** Sets a {@link CarUserManager}. */ + public void setCarUserManager(CarUserManager carUserManager) { + mCarUserManager = carUserManager; + } + private void onUsersUpdate() { mAdapter.clearUsers(); mAdapter.updateUsers(createUserRecords(getUsersForUserGrid())); @@ -273,7 +288,9 @@ public class UserGridRecyclerView extends RecyclerView { notifyUserSelected(userRecord); UserInfo guest = createNewOrFindExistingGuest(mContext); if (guest != null) { - mCarUserManagerHelper.switchToUser(guest); + if (!switchUser(guest.id)) { + Log.e(TAG, "Failed to switch to guest user: " + guest.id); + } } break; case UserRecord.ADD_USER: @@ -289,7 +306,9 @@ public class UserGridRecyclerView extends RecyclerView { // If the user doesn't want to be a guest or add a user, switch to the user // selected notifyUserSelected(userRecord); - mCarUserManagerHelper.switchToUser(userRecord.mInfo); + if (!switchUser(userRecord.mInfo.id)) { + Log.e(TAG, "Failed to switch users: " + userRecord.mInfo.id); + } } }); @@ -430,8 +449,9 @@ public class UserGridRecyclerView extends RecyclerView { */ @Nullable public UserInfo createNewOrFindExistingGuest(Context context) { + AndroidFuture future = mCarUserManager.createGuest(mGuestName); // CreateGuest will return null if a guest already exists. - UserInfo newGuest = mUserManager.createGuest(context, mGuestName); + UserInfo newGuest = getUserInfo(future); if (newGuest != null) { new UserIconProvider().assignDefaultIcon( mUserManager, context.getResources(), newGuest); @@ -444,7 +464,6 @@ public class UserGridRecyclerView extends RecyclerView { @Override public void onClick(DialogInterface dialog, int which) { if (which == BUTTON_POSITIVE) { - notifyUserSelected(mAddUserRecord); new AddNewUserTask().execute(mNewUserName); } else if (which == BUTTON_NEGATIVE) { // Enable the add button only if cancel @@ -462,11 +481,77 @@ public class UserGridRecyclerView extends RecyclerView { } } + @Nullable + private UserInfo getUserInfo(AndroidFuture future) { + UserCreationResult userCreationResult; + try { + userCreationResult = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + Log.w(TAG, "Could not create user.", e); + return null; + } + + if (userCreationResult == null) { + Log.w(TAG, "Timed out while creating user: " + TIMEOUT_MS + "ms"); + return null; + } + if (!userCreationResult.isSuccess() || userCreationResult.getUser() == null) { + Log.w(TAG, "Could not create user: " + userCreationResult); + return null; + } + + return userCreationResult.getUser(); + } + + private boolean switchUser(@UserIdInt int userId) { + AndroidFuture userSwitchResultFuture = + mCarUserManager.switchUser(userId); + UserSwitchResult userSwitchResult; + try { + userSwitchResult = userSwitchResultFuture.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (Exception e) { + Log.w(TAG, "Could not switch user.", e); + return false; + } + + if (userSwitchResult == null) { + Log.w(TAG, "Timed out while switching user: " + TIMEOUT_MS + "ms"); + return false; + } + if (!userSwitchResult.isSuccess()) { + Log.w(TAG, "Could not switch user: " + userSwitchResult); + return false; + } + + return true; + } + + // TODO(b/161539497): Replace AsyncTask with standard {@link java.util.concurrent} code. private class AddNewUserTask extends AsyncTask { @Override protected UserInfo doInBackground(String... userNames) { - return mCarUserManagerHelper.createNewNonAdminUser(userNames[0]); + AndroidFuture future = mCarUserManager.createUser(userNames[0], + /* flags= */ 0); + try { + UserInfo user = getUserInfo(future); + if (user != null) { + UserHelper.setDefaultNonAdminRestrictions(mContext, user, + /* enable= */ true); + UserHelper.assignDefaultIcon(mContext, user); + mAddUserRecord = new UserRecord(user, UserRecord.ADD_USER); + return user; + } else { + Log.e(TAG, "Failed to create user in the background"); + return user; + } + } catch (Exception e) { + if (e instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + Log.e(TAG, "Error creating new user: ", e); + } + return null; } @Override @@ -476,7 +561,11 @@ public class UserGridRecyclerView extends RecyclerView { @Override protected void onPostExecute(UserInfo user) { if (user != null) { - mCarUserManagerHelper.switchToUser(user); + notifyUserSelected(mAddUserRecord); + mAddUserView.setEnabled(true); + if (!switchUser(user.id)) { + Log.e(TAG, "Failed to switch to new user: " + user.id); + } } if (mAddUserView != null) { mAddUserView.setEnabled(true); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java index 45f3d342fb6e8e1a79c872a218da961eaa956c54..0d77c1341ffb601809d767dadd7c1bde6ff53662 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewController.java @@ -91,6 +91,11 @@ public class UserSwitchTransitionViewController extends OverlayViewController { R.integer.config_userSwitchTransitionViewShownTimeoutMs); } + @Override + protected int getInsetTypesToFit() { + return 0; + } + /** * Makes the user switch transition view appear and draws the content inside of it if a user * that is different from the previous user is provided and if the dialog is not already diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java index aea691443290ea809974c5e4b3f48fd0be7de52c..7db2823dc3b998bce7ad8995b11e271a7c083db6 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediator.java @@ -16,12 +16,12 @@ package com.android.systemui.car.userswitcher; -import android.app.ActivityManager; import android.car.Car; import android.car.user.CarUserManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.window.OverlayViewMediator; @@ -36,13 +36,16 @@ public class UserSwitchTransitionViewMediator implements OverlayViewMediator, private static final String TAG = "UserSwitchTransitionViewMediator"; private final CarServiceProvider mCarServiceProvider; + private final CarDeviceProvisionedController mCarDeviceProvisionedController; private final UserSwitchTransitionViewController mUserSwitchTransitionViewController; @Inject public UserSwitchTransitionViewMediator( CarServiceProvider carServiceProvider, + CarDeviceProvisionedController carDeviceProvisionedController, UserSwitchTransitionViewController userSwitchTransitionViewController) { mCarServiceProvider = carServiceProvider; + mCarDeviceProvisionedController = carDeviceProvisionedController; mUserSwitchTransitionViewController = userSwitchTransitionViewController; } @@ -74,7 +77,7 @@ public class UserSwitchTransitionViewMediator implements OverlayViewMediator, @VisibleForTesting void handleUserLifecycleEvent(CarUserManager.UserLifecycleEvent event) { if (event.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING - && ActivityManager.getCurrentUser() == event.getUserId()) { + && mCarDeviceProvisionedController.getCurrentUser() == event.getUserId()) { mUserSwitchTransitionViewController.handleShow(event.getUserId()); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java index 45808a8a0b3e32d02237796940b019c09eee91b3..3c9879c671a54e61d54cceee0a70e5f13b7b2c02 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java @@ -191,6 +191,38 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } } + /** Checks if a {@link MotionEvent} is an action to open the panel. + * @param e {@link MotionEvent} to check. + * @return true only if opening action. + */ + protected boolean isOpeningAction(MotionEvent e) { + if (mAnimateDirection == POSITIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_DOWN; + } + + if (mAnimateDirection == NEGATIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_UP; + } + + return false; + } + + /** Checks if a {@link MotionEvent} is an action to close the panel. + * @param e {@link MotionEvent} to check. + * @return true only if closing action. + */ + protected boolean isClosingAction(MotionEvent e) { + if (mAnimateDirection == POSITIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_UP; + } + + if (mAnimateDirection == NEGATIVE_DIRECTION) { + return e.getActionMasked() == MotionEvent.ACTION_DOWN; + } + + return false; + } + /* ***************************************************************************************** * * Panel Animation * ***************************************************************************************** */ @@ -206,7 +238,6 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } onAnimateCollapsePanel(); - getOverlayViewGlobalStateController().setWindowFocusable(false); animatePanel(mClosingVelocity, /* isClosing= */ true); } @@ -243,8 +274,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController { * Depending on certain conditions, determines whether to fully expand or collapse the panel. */ protected void maybeCompleteAnimation(MotionEvent event) { - if (event.getActionMasked() == MotionEvent.ACTION_UP - && isPanelVisible()) { + if (isClosingAction(event) && isPanelVisible()) { if (mSettleClosePercentage < mPercentageFromEndingEdge) { animatePanel(DEFAULT_FLING_VELOCITY, false); } else { @@ -266,14 +296,17 @@ public abstract class OverlayPanelViewController extends OverlayViewController { float from = getCurrentStartPosition(rect); if (from != to) { animate(from, to, velocity, isClosing); - return; } + + // If we swipe down the notification panel all the way to the bottom of the screen + // (i.e. from == to), then we have finished animating the panel. + return; } // We will only be here if the shade is being opened programmatically or via button when // height of the layout was not calculated. - ViewTreeObserver notificationTreeObserver = getLayout().getViewTreeObserver(); - notificationTreeObserver.addOnGlobalLayoutListener( + ViewTreeObserver panelTreeObserver = getLayout().getViewTreeObserver(); + panelTreeObserver.addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { @@ -381,7 +414,6 @@ public abstract class OverlayPanelViewController extends OverlayViewController { getOverlayViewGlobalStateController().hideView(/* panelViewController= */ this); } getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE); - getOverlayViewGlobalStateController().setWindowFocusable(visible); } /* ***************************************************************************************** * @@ -476,6 +508,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController { return mIsTracking; } + /** Sets whether the panel is currently tracking or not. */ + protected final void setIsTracking(boolean isTracking) { + mIsTracking = isTracking; + } + /** Returns {@code true} if the panel is currently animating. */ protected final boolean isAnimating() { return mIsAnimating; @@ -514,7 +551,7 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } setPanelVisible(true); - // clips the view for the notification shade when the user scrolls to open. + // clips the view for the panel when the user scrolls to open. setViewClipBounds((int) event2.getRawY()); // Initially the scroll starts with height being zero. This checks protects from divide @@ -569,11 +606,11 @@ public abstract class OverlayPanelViewController extends OverlayViewController { boolean isInClosingDirection = mAnimateDirection * distanceY > 0; // This check is to figure out if onScroll was called while swiping the card at - // bottom of the list. At that time we should not allow notification shade to + // bottom of the panel. At that time we should not allow panel to // close. We are also checking for the upwards swipe gesture here because it is - // possible if a user is closing the notification shade and while swiping starts + // possible if a user is closing the panel and while swiping starts // to open again but does not fling. At that time we should allow the - // notification shade to close fully or else it would stuck in between. + // panel to close fully or else it would stuck in between. if (Math.abs(getLayout().getHeight() - y) > SWIPE_DOWN_MIN_DISTANCE && isInClosingDirection) { setViewClipBounds((int) y); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java index 3969f92c690aadc33d04e1d9a1c5629705cd9d9e..8adc1adcc41c4dd932f711dfcdc56742585ca08d 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java @@ -16,9 +16,12 @@ package com.android.systemui.car.window; +import static android.view.WindowInsets.Type.statusBars; + import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; +import android.view.WindowInsets; /** * Owns a {@link View} that is present in SystemUIOverlayWindow. @@ -133,9 +136,18 @@ public class OverlayViewController { } /** - * Returns {@code true} if navigation bar should be displayed over this view. + * Returns {@code true} if navigation bar insets should be displayed over this view. Has no + * effect if {@link #shouldFocusWindow} returns {@code false}. + */ + protected boolean shouldShowNavigationBarInsets() { + return false; + } + + /** + * Returns {@code true} if status bar insets should be displayed over this view. Has no + * effect if {@link #shouldFocusWindow} returns {@code false}. */ - protected boolean shouldShowNavigationBar() { + protected boolean shouldShowStatusBarInsets() { return false; } @@ -145,4 +157,22 @@ public class OverlayViewController { protected boolean shouldShowWhenOccluded() { return false; } + + /** + * Returns {@code true} if the window should be focued when this view is visible. Note that + * returning {@code false} here means that {@link #shouldShowStatusBarInsets} and + * {@link #shouldShowNavigationBarInsets} will have no effect. + */ + protected boolean shouldFocusWindow() { + return true; + } + + /** + * Returns the insets types to fit to the sysui overlay window when this + * {@link OverlayViewController} is in the foreground. + */ + @WindowInsets.Type.InsetsType + protected int getInsetTypesToFit() { + return statusBars(); + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java index 8e94109643131d8abe35110d06e4c1340c36a862..55f0975aeccfa9e147f9842e1f6288c2cc5711a9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java @@ -16,13 +16,16 @@ package com.android.systemui.car.window; +import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; + import android.annotation.Nullable; import android.util.Log; +import android.view.WindowInsets.Type.InsetsType; +import android.view.WindowInsetsController; import androidx.annotation.VisibleForTesting; -import com.android.systemui.car.navigationbar.CarNavigationBarController; - import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -48,10 +51,7 @@ public class OverlayViewGlobalStateController { private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName(); private static final int UNKNOWN_Z_ORDER = -1; private final SystemUIOverlayWindowController mSystemUIOverlayWindowController; - private final CarNavigationBarController mCarNavigationBarController; - - private boolean mIsOccluded; - + private final WindowInsetsController mWindowInsetsController; @VisibleForTesting Map mZOrderMap; @VisibleForTesting @@ -60,14 +60,15 @@ public class OverlayViewGlobalStateController { Set mViewsHiddenForOcclusion; @VisibleForTesting OverlayViewController mHighestZOrder; + private boolean mIsOccluded; @Inject public OverlayViewGlobalStateController( - CarNavigationBarController carNavigationBarController, SystemUIOverlayWindowController systemUIOverlayWindowController) { mSystemUIOverlayWindowController = systemUIOverlayWindowController; mSystemUIOverlayWindowController.attach(); - mCarNavigationBarController = carNavigationBarController; + mWindowInsetsController = + mSystemUIOverlayWindowController.getBaseLayout().getWindowInsetsController(); mZOrderMap = new HashMap<>(); mZOrderVisibleSortedMap = new TreeMap<>(); mViewsHiddenForOcclusion = new HashSet<>(); @@ -115,7 +116,10 @@ public class OverlayViewGlobalStateController { } updateInternalsWhenShowingView(viewController); + refreshInsetTypesToFit(); + refreshWindowFocus(); refreshNavigationBarVisibility(); + refreshStatusBarVisibility(); Log.d(TAG, "Content shown: " + viewController.getClass().getName()); debugLog(); @@ -185,7 +189,10 @@ public class OverlayViewGlobalStateController { mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController)); refreshHighestZOrderWhenHidingView(viewController); + refreshInsetTypesToFit(); + refreshWindowFocus(); refreshNavigationBarVisibility(); + refreshStatusBarVisibility(); if (mZOrderVisibleSortedMap.isEmpty()) { setWindowVisible(false); @@ -208,10 +215,42 @@ public class OverlayViewGlobalStateController { } private void refreshNavigationBarVisibility() { - if (mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowNavigationBar()) { - mCarNavigationBarController.showBars(); + if (mZOrderVisibleSortedMap.isEmpty()) { + mWindowInsetsController.show(navigationBars()); + return; + } + + // Do not hide navigation bar insets if the window is not focusable. + if (mHighestZOrder.shouldFocusWindow() && !mHighestZOrder.shouldShowNavigationBarInsets()) { + mWindowInsetsController.hide(navigationBars()); } else { - mCarNavigationBarController.hideBars(); + mWindowInsetsController.show(navigationBars()); + } + } + + private void refreshStatusBarVisibility() { + if (mZOrderVisibleSortedMap.isEmpty()) { + mWindowInsetsController.show(statusBars()); + return; + } + + // Do not hide status bar insets if the window is not focusable. + if (mHighestZOrder.shouldFocusWindow() && !mHighestZOrder.shouldShowStatusBarInsets()) { + mWindowInsetsController.hide(statusBars()); + } else { + mWindowInsetsController.show(statusBars()); + } + } + + private void refreshWindowFocus() { + setWindowFocusable(mHighestZOrder == null ? false : mHighestZOrder.shouldFocusWindow()); + } + + private void refreshInsetTypesToFit() { + if (mZOrderVisibleSortedMap.isEmpty()) { + setFitInsetsTypes(statusBars()); + } else { + setFitInsetsTypes(mHighestZOrder.getInsetTypesToFit()); } } @@ -224,6 +263,10 @@ public class OverlayViewGlobalStateController { mSystemUIOverlayWindowController.setWindowVisible(visible); } + private void setFitInsetsTypes(@InsetsType int types) { + mSystemUIOverlayWindowController.setFitInsetsTypes(types); + } + /** * Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the * sysui overlay window. diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java index bcd96f63a2b44719ea51c054ac7e2f35f89d4111..c955fab592f308f9a8cacaa2de3f06e2bfbf4526 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java @@ -16,6 +16,7 @@ package com.android.systemui.car.window; +import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import android.content.Context; @@ -25,6 +26,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.WindowManager; import com.android.systemui.R; @@ -99,17 +101,23 @@ public class SystemUIOverlayWindowController implements PixelFormat.TRANSLUCENT); mLp.token = new Binder(); mLp.gravity = Gravity.TOP; - mLp.setFitInsetsTypes(/* types= */ 0); mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("SystemUIOverlayWindow"); mLp.packageName = mContext.getPackageName(); mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; + mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; mWindowManager.addView(mBaseLayout, mLp); mLpChanged.copyFrom(mLp); setWindowVisible(false); } + /** Sets the types of insets to fit. Note: This should be rarely used. */ + public void setFitInsetsTypes(@WindowInsets.Type.InsetsType int types) { + mLpChanged.setFitInsetsTypes(types); + updateWindow(); + } + /** Sets the window to the visible state. */ public void setWindowVisible(boolean visible) { mVisible = visible; @@ -154,6 +162,7 @@ public class SystemUIOverlayWindowController implements private void updateWindow() { if (mLp != null && mLp.copyFrom(mLpChanged) != 0) { if (isAttached()) { + mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; mWindowManager.updateViewLayout(mBaseLayout, mLp); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java new file mode 100644 index 0000000000000000000000000000000000000000..5f9665ff7632bb261ecf5dc6585273d7aa7e9f35 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import android.car.settings.CarSettings; +import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.ArraySet; +import android.util.Slog; +import android.view.WindowInsets; + +import androidx.annotation.VisibleForTesting; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Util class to load PolicyControl and allow for querying if a package matches immersive filters. + * Similar to {@link com.android.server.wm.PolicyControl}, but separate due to CarSystemUI needing + * to set its own policies for system bar visibilities. + * + * This forces immersive mode behavior for one or both system bars (based on a package + * list). + * + * Control by setting {@link Settings.Global#POLICY_CONTROL_AUTO} to one or more name-value pairs. + * e.g. + * to force immersive mode everywhere: + * "immersive.full=*" + * to force hide status bars for com.package1 but not com.package2: + * "immersive.status=com.package1,-com.package2" + * + * Separate multiple name-value pairs with ':' + * e.g. "immersive.status=com.package:immersive.navigation=*" + */ +public class BarControlPolicy { + + private static final String TAG = "BarControlPolicy"; + private static final boolean DEBUG = false; + + private static final String NAME_IMMERSIVE_FULL = "immersive.full"; + private static final String NAME_IMMERSIVE_STATUS = "immersive.status"; + private static final String NAME_IMMERSIVE_NAVIGATION = "immersive.navigation"; + + @VisibleForTesting + static String sSettingValue; + @VisibleForTesting + static Filter sImmersiveStatusFilter; + private static Filter sImmersiveNavigationFilter; + + /** Loads values from the POLICY_CONTROL setting to set filters. */ + static boolean reloadFromSetting(Context context) { + if (DEBUG) Slog.d(TAG, "reloadFromSetting()"); + String value = null; + try { + value = Settings.Global.getStringForUser(context.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + UserHandle.USER_CURRENT); + if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) { + return false; + } + setFilters(value); + sSettingValue = value; + } catch (Throwable t) { + Slog.w(TAG, "Error loading policy control, value=" + value, t); + return false; + } + return true; + } + + /** Used in testing to reset BarControlPolicy. */ + @VisibleForTesting + static void reset() { + sSettingValue = null; + sImmersiveStatusFilter = null; + sImmersiveNavigationFilter = null; + } + + /** + * Registers a content observer to listen to updates to the SYSTEM_BAR_VISIBILITY_OVERRIDE flag. + */ + static void registerContentObserver(Context context, Handler handler, FilterListener listener) { + context.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE), false, + new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange) { + if (reloadFromSetting(context)) { + listener.onFilterUpdated(); + } + } + }, UserHandle.USER_ALL); + } + + /** + * Returns bar visibilities based on POLICY_CONTROL_AUTO filters and window policies. + * @return int[], where the first value is the inset types that should be shown, and the second + * is the inset types that should be hidden. + */ + @WindowInsets.Type.InsetsType + static int[] getBarVisibilities(String packageName) { + int hideTypes = 0; + int showTypes = 0; + if (matchesStatusFilter(packageName)) { + hideTypes |= WindowInsets.Type.statusBars(); + } else { + showTypes |= WindowInsets.Type.statusBars(); + } + if (matchesNavigationFilter(packageName)) { + hideTypes |= WindowInsets.Type.navigationBars(); + } else { + showTypes |= WindowInsets.Type.navigationBars(); + } + + return new int[] {showTypes, hideTypes}; + } + + private static boolean matchesStatusFilter(String packageName) { + return sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(packageName); + } + + private static boolean matchesNavigationFilter(String packageName) { + return sImmersiveNavigationFilter != null + && sImmersiveNavigationFilter.matches(packageName); + } + + private static void setFilters(String value) { + if (DEBUG) Slog.d(TAG, "setFilters: " + value); + sImmersiveStatusFilter = null; + sImmersiveNavigationFilter = null; + if (value != null) { + String[] nvps = value.split(":"); + for (String nvp : nvps) { + int i = nvp.indexOf('='); + if (i == -1) continue; + String n = nvp.substring(0, i); + String v = nvp.substring(i + 1); + if (n.equals(NAME_IMMERSIVE_FULL)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = sImmersiveNavigationFilter = f; + } else if (n.equals(NAME_IMMERSIVE_STATUS)) { + Filter f = Filter.parse(v); + sImmersiveStatusFilter = f; + } else if (n.equals(NAME_IMMERSIVE_NAVIGATION)) { + Filter f = Filter.parse(v); + sImmersiveNavigationFilter = f; + } + } + } + if (DEBUG) { + Slog.d(TAG, "immersiveStatusFilter: " + sImmersiveStatusFilter); + Slog.d(TAG, "immersiveNavigationFilter: " + sImmersiveNavigationFilter); + } + } + + private static class Filter { + private static final String ALL = "*"; + + private final ArraySet mWhitelist; + private final ArraySet mBlacklist; + + private Filter(ArraySet whitelist, ArraySet blacklist) { + mWhitelist = whitelist; + mBlacklist = blacklist; + } + + boolean matches(String packageName) { + if (packageName == null) return false; + if (onBlacklist(packageName)) return false; + return onWhitelist(packageName); + } + + private boolean onBlacklist(String packageName) { + return mBlacklist.contains(packageName) || mBlacklist.contains(ALL); + } + + private boolean onWhitelist(String packageName) { + return mWhitelist.contains(ALL) || mWhitelist.contains(packageName); + } + + void dump(PrintWriter pw) { + pw.print("Filter["); + dump("whitelist", mWhitelist, pw); pw.print(','); + dump("blacklist", mBlacklist, pw); pw.print(']'); + } + + private void dump(String name, ArraySet set, PrintWriter pw) { + pw.print(name); pw.print("=("); + int n = set.size(); + for (int i = 0; i < n; i++) { + if (i > 0) pw.print(','); + pw.print(set.valueAt(i)); + } + pw.print(')'); + } + + @Override + public String toString() { + StringWriter sw = new StringWriter(); + dump(new PrintWriter(sw, true)); + return sw.toString(); + } + + // value = comma-delimited list of tokens, where token = (package name|*) + // e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*" + static Filter parse(String value) { + if (value == null) return null; + ArraySet whitelist = new ArraySet(); + ArraySet blacklist = new ArraySet(); + for (String token : value.split(",")) { + token = token.trim(); + if (token.startsWith("-") && token.length() > 1) { + token = token.substring(1); + blacklist.add(token); + } else { + whitelist.add(token); + } + } + return new Filter(whitelist, blacklist); + } + } + + /** + * Interface to listen for updates to the filter triggered by the content observer listening to + * the SYSTEM_BAR_VISIBILITY_OVERRIDE flag. + */ + interface FilterListener { + + /** Callback triggered when the content observer updates the filter. */ + void onFilterUpdated(); + } + + private BarControlPolicy() {} +} diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java new file mode 100644 index 0000000000000000000000000000000000000000..c9ec34fd5f088e5e81870203379e996922bac77f --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import android.os.Handler; +import android.os.RemoteException; +import android.util.ArraySet; +import android.util.Slog; +import android.util.SparseArray; +import android.view.IDisplayWindowInsetsController; +import android.view.InsetsController; +import android.view.InsetsSourceControl; +import android.view.InsetsState; +import android.view.WindowInsets; + +import androidx.annotation.VisibleForTesting; + +import com.android.systemui.TransactionPool; +import com.android.systemui.dagger.qualifiers.Main; + +import java.util.Objects; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to + * give system bar control to SystemUI. + * {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller + * takes control or not. + */ +@Singleton +public class DisplaySystemBarsController extends DisplayImeController { + + private static final String TAG = "DisplaySystemBarsController"; + + private SparseArray mPerDisplaySparseArray; + + @Inject + public DisplaySystemBarsController( + SystemWindows syswin, + DisplayController displayController, + @Main Handler mainHandler, + TransactionPool transactionPool) { + super(syswin, displayController, mainHandler, transactionPool); + } + + @Override + public void onDisplayAdded(int displayId) { + PerDisplay pd = new PerDisplay(displayId); + try { + mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to set insets controller on display " + displayId); + } + // Lazy loading policy control filters instead of during boot. + if (mPerDisplaySparseArray == null) { + mPerDisplaySparseArray = new SparseArray<>(); + BarControlPolicy.reloadFromSetting(mSystemWindows.mContext); + BarControlPolicy.registerContentObserver(mSystemWindows.mContext, mHandler, () -> { + int size = mPerDisplaySparseArray.size(); + for (int i = 0; i < size; i++) { + mPerDisplaySparseArray.valueAt(i).modifyDisplayWindowInsets(); + } + }); + } + mPerDisplaySparseArray.put(displayId, pd); + } + + @Override + public void onDisplayRemoved(int displayId) { + try { + mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to remove insets controller on display " + displayId); + } + mPerDisplaySparseArray.remove(displayId); + } + + @VisibleForTesting + class PerDisplay extends DisplayImeController.PerDisplay { + + int mDisplayId; + InsetsController mInsetsController; + InsetsState mInsetsState = new InsetsState(); + String mPackageName; + + PerDisplay(int displayId) { + super(displayId, + mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()); + mDisplayId = displayId; + mInsetsController = new InsetsController( + new DisplaySystemBarsInsetsControllerHost(mHandler, this)); + } + + @Override + public void insetsChanged(InsetsState insetsState) { + super.insetsChanged(insetsState); + if (mInsetsState.equals(insetsState)) { + return; + } + mInsetsState.set(insetsState, true /* copySources */); + mInsetsController.onStateChanged(insetsState); + if (mPackageName != null) { + modifyDisplayWindowInsets(); + } + } + + @Override + public void insetsControlChanged(InsetsState insetsState, + InsetsSourceControl[] activeControls) { + super.insetsControlChanged(insetsState, activeControls); + mInsetsController.onControlsChanged(activeControls); + } + + @Override + public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { + if ((types & WindowInsets.Type.ime()) == 0) { + mInsetsController.hide(types); + } else { + super.hideInsets(types, fromIme); + } + + } + + @Override + public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { + if ((types & WindowInsets.Type.ime()) == 0) { + mInsetsController.show(types); + } else { + super.showInsets(types, fromIme); + } + + } + + @Override + public void topFocusedWindowChanged(String packageName) { + if (Objects.equals(mPackageName, packageName)) { + return; + } + mPackageName = packageName; + modifyDisplayWindowInsets(); + } + + private void modifyDisplayWindowInsets() { + if (mPackageName == null) { + return; + } + int[] barVisibilities = BarControlPolicy.getBarVisibilities(mPackageName); + updateInsetsState(barVisibilities[0], /* visible= */ true); + updateInsetsState(barVisibilities[1], /* visible= */ false); + showInsets(barVisibilities[0], /* fromIme= */ false); + hideInsets(barVisibilities[1], /* fromIme= */ false); + try { + mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to update window manager service."); + } + } + + private void updateInsetsState(@WindowInsets.Type.InsetsType int types, boolean visible) { + ArraySet internalTypes = InsetsState.toInternalType(types); + for (int i = internalTypes.size() - 1; i >= 0; i--) { + mInsetsState.getSource(internalTypes.valueAt(i)).setVisible(visible); + } + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java new file mode 100644 index 0000000000000000000000000000000000000000..2f8da44ba8518db3203553d45a9f53019eb31236 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsInsetsControllerHost.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.IDisplayWindowInsetsController; +import android.view.InsetsController; +import android.view.InsetsState; +import android.view.SurfaceControl; +import android.view.SyncRtSurfaceTransactionApplier; +import android.view.WindowInsets; +import android.view.WindowInsetsAnimation; +import android.view.WindowInsetsController; +import android.view.inputmethod.InputMethodManager; + +import java.util.List; + +/** + * Implements {@link InsetsController.Host} for usage by + * {@link DisplaySystemBarsController.PerDisplay} instances in {@link DisplaySystemBarsController}. + * @hide + */ +public class DisplaySystemBarsInsetsControllerHost implements InsetsController.Host { + + private static final String TAG = DisplaySystemBarsInsetsControllerHost.class.getSimpleName(); + + private final Handler mHandler; + private final IDisplayWindowInsetsController mController; + private final float[] mTmpFloat9 = new float[9]; + + public DisplaySystemBarsInsetsControllerHost( + Handler handler, IDisplayWindowInsetsController controller) { + mHandler = handler; + mController = controller; + } + + @Override + public Handler getHandler() { + return mHandler; + } + + @Override + public void notifyInsetsChanged() { + // no-op + } + + @Override + public void dispatchWindowInsetsAnimationPrepare(@NonNull WindowInsetsAnimation animation) { + // no-op + } + + @Override + public WindowInsetsAnimation.Bounds dispatchWindowInsetsAnimationStart( + @NonNull WindowInsetsAnimation animation, + @NonNull WindowInsetsAnimation.Bounds bounds) { + return null; + } + + @Override + public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, + @NonNull List runningAnimations) { + return null; + } + + @Override + public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { + // no-op + } + + @Override + public void applySurfaceParams(final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { + for (int i = params.length - 1; i >= 0; i--) { + SyncRtSurfaceTransactionApplier.applyParams( + new SurfaceControl.Transaction(), params[i], mTmpFloat9); + } + + } + + @Override + public void updateCompatSysUiVisibility( + @InsetsState.InternalInsetsType int type, boolean visible, boolean hasControl) { + // no-op + } + + @Override + public void onInsetsModified(InsetsState insetsState) { + try { + mController.insetsChanged(insetsState); + } catch (RemoteException e) { + Log.e(TAG, "Failed to send insets to controller"); + } + } + + @Override + public boolean hasAnimationCallbacks() { + return false; + } + + @Override + public void setSystemBarsAppearance( + @WindowInsetsController.Appearance int appearance, + @WindowInsetsController.Appearance int mask) { + // no-op + } + + @Override + public @WindowInsetsController.Appearance int getSystemBarsAppearance() { + return 0; + } + + @Override + public void setSystemBarsBehavior(@WindowInsetsController.Behavior int behavior) { + // no-op + } + + @Override + public @WindowInsetsController.Behavior int getSystemBarsBehavior() { + return 0; + } + + @Override + public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { + surfaceControl.release(); + } + + @Override + public void addOnPreDrawRunnable(Runnable r) { + mHandler.post(r); + } + + @Override + public void postInsetsAnimationCallback(Runnable r) { + mHandler.post(r); + } + + @Override + public InputMethodManager getInputMethodManager() { + return null; + } + + @Override + public String getRootViewTitle() { + return null; + } + + @Override + public int dipToPx(int dips) { + return 0; + } + + @Override + public IBinder getWindowToken() { + return null; + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java index fe59cbf20a13cb3be20c82c12df8b5b975e18646..d769cacadf1da869e9b69d0d1cc4a5d32cd5b08e 100644 --- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java +++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java @@ -33,6 +33,7 @@ import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,6 +56,7 @@ import java.util.Collections; * test suite causes errors, such as the incorrect settings provider being cached. * For an example, see {@link com.android.systemui.DependencyTest}. */ +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @SmallTest public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase { 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 7996170ba7d62f150c7019cade1852b80669bb67..e179ef1ce2a4186654ee45559cbb01fd6c0ebc41 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 @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; @@ -39,6 +40,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java index 189e240169c3da83b6f0c0e7391684d30f81d866..62dc2362452004921ccd75b6a29e530594c84d7e 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java @@ -41,6 +41,7 @@ import com.android.keyguard.ViewMediatorCallback; 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.car.navigationbar.CarNavigationBarController; import com.android.systemui.car.window.OverlayViewGlobalStateController; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -59,6 +60,7 @@ import org.mockito.MockitoAnnotations; import dagger.Lazy; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java index a57736bb3502c4734463a56935d7aa4c73f1a8f8..4b826805232459d83894087bfdd14f74b77275ce 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java @@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.tests.R; import org.junit.Before; @@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations; import java.util.List; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java index 893057e222a9a8e7c3385bb3e58a059b20b7f934..f623c26d12b68210d3f88ccffb774ce454682fea 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java @@ -28,6 +28,7 @@ import android.widget.LinearLayout; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.tests.R; import org.junit.Before; @@ -38,6 +39,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java index e84e42c77245d3dad7f3f0ba8d481ee58eebca10..3fd0852bc0fff93ce1d29336cb35c9b5647eb63f 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java @@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.car.hvac.HvacController; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -41,11 +42,16 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest public class CarNavigationBarControllerTest extends SysuiTestCase { + private static final String TOP_NOTIFICATION_PANEL = + "com.android.systemui.car.notification.TopNotificationPanelViewMediator"; + private static final String BOTTOM_NOTIFICATION_PANEL = + "com.android.systemui.car.notification.BottomNotificationPanelViewMediator"; private CarNavigationBarController mCarNavigationBar; private NavigationBarViewFactory mNavigationBarViewFactory; private TestableResources mTestableResources; @@ -71,7 +77,8 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { private CarNavigationBarController createNavigationBarController() { return new CarNavigationBarController(mContext, mNavigationBarViewFactory, mButtonSelectionStateController, () -> mHvacController, - mButtonRoleHolderController); + mButtonRoleHolderController, + new SystemBarConfigs(mTestableResources.getResources())); } @Test @@ -114,6 +121,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetTopWindow_topDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, false); + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + // If Top Notification Panel is used but top navigation bar is not enabled, SystemUI is + // expected to crash. + mTestableResources.addOverride(R.string.config_notificationPanelViewMediator, + BOTTOM_NOTIFICATION_PANEL); mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getTopWindow(); @@ -145,6 +157,11 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetBottomWindow_bottomDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false); + mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true); + // If Bottom Notification Panel is used but bottom navigation bar is not enabled, + // SystemUI is expected to crash. + mTestableResources.addOverride(R.string.config_notificationPanelViewMediator, + TOP_NOTIFICATION_PANEL); mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -233,6 +250,28 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { assertThat(window1).isEqualTo(window2); } + @Test + public void testSetTopWindowVisibility_setTrue_isVisible() { + mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true); + mCarNavigationBar = createNavigationBarController(); + + ViewGroup window = mCarNavigationBar.getTopWindow(); + mCarNavigationBar.setTopWindowVisibility(View.VISIBLE); + + assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testSetTopWindowVisibility_setFalse_isGone() { + mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true); + mCarNavigationBar = createNavigationBarController(); + + ViewGroup window = mCarNavigationBar.getTopWindow(); + mCarNavigationBar.setTopWindowVisibility(View.GONE); + + assertThat(window.getVisibility()).isEqualTo(View.GONE); + } + @Test public void testSetBottomWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java index 0caa86f0eab28881e944967638c9da1403eb92f8..2b5af71dccaab54ba15332f0a9e6c4fb46164596 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java @@ -45,6 +45,7 @@ import com.android.internal.view.AppearanceRegion; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.AutoHideController; import com.android.systemui.statusbar.phone.LightBarController; @@ -63,6 +64,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -140,7 +142,7 @@ public class CarNavigationBarTest extends SysuiTestCase { mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext), mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor, mBarService, () -> mKeyguardStateController, () -> mIconPolicy, - () -> mIconController); + () -> mIconController, new SystemBarConfigs(mTestableResources.getResources())); } @Test diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java index 19e394f69af4d20e518caaecb11ce0c11a01b8ab..47fd8201d197a6a01eb693488507b1de311f5ef5 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java @@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import org.junit.After; import org.junit.Before; @@ -38,6 +39,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java index bcaa5e9a03ee70f26eb9eb9da54e1867606c3a90..173f5487c728be460994e4d69dc4affed748222a 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java @@ -37,6 +37,7 @@ import android.widget.LinearLayout; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.statusbar.AlphaOptimizedImageView; import com.android.systemui.tests.R; @@ -45,6 +46,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..96f05045cd38c4148078dbab93b501f1cfc3bfb3 --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.car.navigationbar; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.content.res.Resources; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.WindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; +import com.android.systemui.car.notification.NotificationPanelViewController; +import com.android.systemui.car.notification.NotificationPanelViewMediator; +import com.android.systemui.car.notification.PowerManagerHelper; +import com.android.systemui.car.notification.TopNotificationPanelViewMediator; +import com.android.systemui.statusbar.policy.ConfigurationController; + +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; +import java.util.List; + +@CarSystemUiTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class SystemBarConfigsTest extends SysuiTestCase { + + private SystemBarConfigs mSystemBarConfigs; + @Mock + private Resources mResources; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + setDefaultValidConfig(); + } + + @Test + public void onInit_allSystemBarsEnabled_eachHasUniqueBarTypes_doesNotThrowException() { + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test(expected = RuntimeException.class) + public void onInit_allSystemBarsEnabled_twoBarsHaveDuplicateType_throwsRuntimeException() { + when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0); + when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(0); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test + public void onInit_allSystemBarsEnabled_systemBarSidesSortedByZOrder() { + mSystemBarConfigs = new SystemBarConfigs(mResources); + List actualOrder = mSystemBarConfigs.getSystemBarSidesByZOrder(); + List expectedOrder = new ArrayList<>(); + expectedOrder.add(SystemBarConfigs.LEFT); + expectedOrder.add(SystemBarConfigs.RIGHT); + expectedOrder.add(SystemBarConfigs.TOP); + expectedOrder.add(SystemBarConfigs.BOTTOM); + + assertTrue(actualOrder.equals(expectedOrder)); + } + + @Test(expected = RuntimeException.class) + public void onInit_intersectingBarsHaveSameZOrder_throwsRuntimeException() { + when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(33); + when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(33); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test(expected = RuntimeException.class) + public void onInit_hideBottomSystemBarForKeyboardValueDoNotSync_throwsRuntimeException() { + when(mResources.getBoolean(R.bool.config_hideBottomSystemBarForKeyboard)).thenReturn(false); + when(mResources.getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard)).thenReturn( + true); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test + public void onInit_topNotifPanelViewMediatorUsed_topBarEnabled_doesNotThrowException() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true); + when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn( + TestTopNotificationPanelViewMediator.class.getName()); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test(expected = RuntimeException.class) + public void onInit_topNotifPanelViewMediatorUsed_topBarNotEnabled_throwsRuntimeException() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false); + when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn( + TestTopNotificationPanelViewMediator.class.getName()); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test + public void onInit_notificationPanelViewMediatorUsed_topBarNotEnabled_doesNotThrowException() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false); + when(mResources.getString(R.string.config_notificationPanelViewMediator)).thenReturn( + NotificationPanelViewMediator.class.getName()); + + mSystemBarConfigs = new SystemBarConfigs(mResources); + } + + @Test + public void getTopSystemBarLayoutParams_topBarEnabled_returnsTopSystemBarLayoutParams() { + mSystemBarConfigs = new SystemBarConfigs(mResources); + WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide( + SystemBarConfigs.TOP); + + assertNotNull(lp); + } + + @Test + public void getTopSystemBarLayoutParams_topBarNotEnabled_returnsNull() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false); + mSystemBarConfigs = new SystemBarConfigs(mResources); + WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide( + SystemBarConfigs.TOP); + + assertNull(lp); + } + + @Test + public void getTopSystemBarHideForKeyboard_hideBarForKeyboard_returnsTrue() { + when(mResources.getBoolean(R.bool.config_hideTopSystemBarForKeyboard)).thenReturn(true); + mSystemBarConfigs = new SystemBarConfigs(mResources); + + boolean hideKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP); + + assertTrue(hideKeyboard); + } + + @Test + public void getTopSystemBarHideForKeyboard_topBarNotEnabled_returnsFalse() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false); + mSystemBarConfigs = new SystemBarConfigs(mResources); + + boolean hideKeyboard = mSystemBarConfigs.getHideForKeyboardBySide(SystemBarConfigs.TOP); + + assertFalse(hideKeyboard); + } + + @Test + public void topSystemBarHasHigherZOrderThanHuns_topSystemBarIsNavigationBarPanelType() { + when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn( + SystemBarConfigs.getHunZOrder() + 1); + mSystemBarConfigs = new SystemBarConfigs(mResources); + WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide( + SystemBarConfigs.TOP); + + assertEquals(lp.type, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL); + } + + @Test + public void topSystemBarHasLowerZOrderThanHuns_topSystemBarIsStatusBarAdditionalType() { + when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn( + SystemBarConfigs.getHunZOrder() - 1); + mSystemBarConfigs = new SystemBarConfigs(mResources); + WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide( + SystemBarConfigs.TOP); + + assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL); + } + + // Set valid config where all system bars are enabled. + private void setDefaultValidConfig() { + when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_enableBottomNavigationBar)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_enableLeftNavigationBar)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true); + + when(mResources.getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_height)).thenReturn(100); + when(mResources.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100); + when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn( + 100); + when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn( + 100); + + when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0); + when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1); + when(mResources.getInteger(R.integer.config_leftSystemBarType)).thenReturn(2); + when(mResources.getInteger(R.integer.config_rightSystemBarType)).thenReturn(3); + + when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(5); + when(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).thenReturn(10); + when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(2); + when(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).thenReturn(3); + + when(mResources.getBoolean(R.bool.config_hideTopSystemBarForKeyboard)).thenReturn(false); + when(mResources.getBoolean( + com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard)).thenReturn( + false); + when(mResources.getBoolean(R.bool.config_hideLeftSystemBarForKeyboard)).thenReturn( + false); + when(mResources.getBoolean(R.bool.config_hideRightSystemBarForKeyboard)).thenReturn( + false); + } + + // Intentionally using a subclass of TopNotificationPanelViewMediator for testing purposes to + // ensure that OEM's will be able to implement and use their own NotificationPanelViewMediator. + private class TestTopNotificationPanelViewMediator extends + TopNotificationPanelViewMediator { + TestTopNotificationPanelViewMediator( + CarNavigationBarController carNavigationBarController, + NotificationPanelViewController notificationPanelViewController, + PowerManagerHelper powerManagerHelper, + BroadcastDispatcher broadcastDispatcher, + CarDeviceProvisionedController carDeviceProvisionedController, + ConfigurationController configurationController) { + super(carNavigationBarController, notificationPanelViewController, powerManagerHelper, + broadcastDispatcher, carDeviceProvisionedController, configurationController); + } + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java index ccaeb458fe5467f7e341a99532e33c08f6fb3e9d..384888ab42c3c52846de86901f3ecc6550d58496 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java @@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.car.window.OverlayViewGlobalStateController; import org.junit.Before; @@ -38,6 +39,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java index 89dac58cd2a7324c52a5d87d43f82e1004e1e320..d51aeb18135d5f98aed67c570da5f9239a4c505e 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java @@ -37,6 +37,7 @@ import com.android.car.notification.NotificationDataManager; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations; import java.util.Collections; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java index 77620f3fb345b43b5ab2f86ee816cc7b8949989d..421e2109356d12c8e92225adc1cb0d609b8ffec1 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java @@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; @@ -44,6 +45,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java index 73f9f6a55afca17bda0acf490cf0b8aaa82f39d1..67f222b9e29abc9cb4643eaf5bd6fb7a809c87f9 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java @@ -35,6 +35,7 @@ import android.view.DisplayInfo; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; @@ -46,6 +47,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -218,7 +220,7 @@ public class SideLoadedAppListenerTest extends SysuiTestCase { verify(mSideLoadedAppStateController, never()).onUnsafeTaskCreatedOnDisplay(any()); verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display1); - verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display2); + verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2); verify(mSideLoadedAppStateController).onSafeTaskDisplayedOnDisplay(display3); verify(mSideLoadedAppStateController, never()).onUnsafeTaskDisplayedOnDisplay(display1); verify(mSideLoadedAppStateController).onUnsafeTaskDisplayedOnDisplay(display2); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java index 797dbf515b7ec0e317f8377a59686b21c808d8c5..2e9d43b595a1590bc3d958eb17ddaf89face14d4 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java @@ -36,6 +36,7 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.car.window.OverlayViewGlobalStateController; import org.junit.Before; @@ -44,6 +45,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java index a808e2d40e26ef41ed6d25971d0ddc278dd6f87c..7aeffce7042dff736b22b042765af1e7876f1f5c 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java @@ -16,6 +16,7 @@ package com.android.systemui.car.userswitcher; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -24,7 +25,10 @@ import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; @@ -32,16 +36,19 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest -public class UserSwitchTransitionViewMediatorTest { +public class UserSwitchTransitionViewMediatorTest extends SysuiTestCase { private static final int TEST_USER = 100; private UserSwitchTransitionViewMediator mUserSwitchTransitionViewMediator; @Mock private CarServiceProvider mCarServiceProvider; @Mock + private CarDeviceProvisionedController mCarDeviceProvisionedController; + @Mock private UserSwitchTransitionViewController mUserSwitchTransitionViewController; @Mock private CarUserManager.UserLifecycleEvent mUserLifecycleEvent; @@ -51,20 +58,34 @@ public class UserSwitchTransitionViewMediatorTest { MockitoAnnotations.initMocks(this); mUserSwitchTransitionViewMediator = new UserSwitchTransitionViewMediator( - mCarServiceProvider, mUserSwitchTransitionViewController); - + mCarServiceProvider, mCarDeviceProvisionedController, + mUserSwitchTransitionViewController); + when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER); } @Test - public void onUserLifecycleEvent_userStarting_callsHandleShow() { + public void onUserLifecycleEvent_userStarting_isCurrentUser_callsHandleShow() { when(mUserLifecycleEvent.getEventType()).thenReturn( CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING); when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER); + mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent); verify(mUserSwitchTransitionViewController).handleShow(TEST_USER); } + @Test + public void onUserLifecycleEvent_userStarting_isNotCurrentUser_doesNotCallHandleShow() { + when(mUserLifecycleEvent.getEventType()).thenReturn( + CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING); + when(mUserLifecycleEvent.getUserId()).thenReturn(TEST_USER); + when(mCarDeviceProvisionedController.getCurrentUser()).thenReturn(TEST_USER + 1); + + mUserSwitchTransitionViewMediator.handleUserLifecycleEvent(mUserLifecycleEvent); + + verify(mUserSwitchTransitionViewController, never()).handleShow(TEST_USER); + } + @Test public void onUserLifecycleEvent_userSwitching_callsHandleHide() { when(mUserLifecycleEvent.getEventType()).thenReturn( diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java index eca51e34995ccf024c0dd32b7f953d8cac173eb5..f77294e37b9816d4ee8a002cd3920b14dbb48bdb 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java @@ -19,11 +19,15 @@ package com.android.systemui.car.voicerecognition; import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE; import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.content.Intent; import android.os.Handler; @@ -33,25 +37,36 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest +// TODO(b/162866441): Refactor to use the Executor pattern instead. public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase { private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; + private static final String BLUETOOTH_REMOTE_ADDRESS = "00:11:22:33:44:55"; private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier; + private TestableLooper mTestableLooper; + private Handler mHandler; private Handler mTestHandler; + private BluetoothDevice mBluetoothDevice; @Before public void setUp() throws Exception { - TestableLooper testableLooper = TestableLooper.get(this); - mTestHandler = spy(new Handler(testableLooper.getLooper())); + mTestableLooper = TestableLooper.get(this); + mHandler = new Handler(mTestableLooper.getLooper()); + mTestHandler = spy(mHandler); + mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice( + BLUETOOTH_REMOTE_ADDRESS); mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier( mContext, mTestHandler); mVoiceRecognitionNotifier.onBootCompleted(); @@ -61,37 +76,60 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase { public void testReceiveIntent_started_showToast() { Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, VOICE_RECOGNITION_STARTED); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + mTestableLooper.processAllMessages(); waitForIdleSync(); - verify(mTestHandler).post(any()); + mHandler.post(() -> { + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mTestHandler).post(argumentCaptor.capture()); + assertThat(argumentCaptor.getValue()).isNotNull(); + assertThat(argumentCaptor.getValue()).isNotEqualTo(this); + }); } @Test public void testReceiveIntent_invalidExtra_noToast() { Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); intent.putExtra(BluetoothHeadsetClient.EXTRA_VOICE_RECOGNITION, INVALID_VALUE); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + mTestableLooper.processAllMessages(); waitForIdleSync(); - verify(mTestHandler, never()).post(any()); + mHandler.post(() -> { + verify(mTestHandler, never()).post(any()); + }); } @Test public void testReceiveIntent_noExtra_noToast() { Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AG_EVENT); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + mTestableLooper.processAllMessages(); waitForIdleSync(); - verify(mTestHandler, never()).post(any()); + mHandler.post(() -> { + verify(mTestHandler, never()).post(any()); + }); } @Test public void testReceiveIntent_invalidIntent_noToast() { Intent intent = new Intent(BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mBluetoothDevice); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + mTestableLooper.processAllMessages(); waitForIdleSync(); - verify(mTestHandler, never()).post(any()); + mHandler.post(() -> { + verify(mTestHandler, never()).post(any()); + }); } } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java index 45a05ac69bd7a91058e278ece78334b27b55cfac..23e21e4cbed68f6c0061999f2f148dde5741f8aa 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java @@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.tests.R; @@ -52,6 +53,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -221,18 +223,6 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.getLayout().getHeight()); } - @Test - public void animateCollapsePanel_removesWindowFocus() { - mOverlayPanelViewController.inflate(mBaseLayout); - mOverlayPanelViewController.setShouldAnimateCollapsePanel(true); - mOverlayPanelViewController.setPanelExpanded(true); - mOverlayPanelViewController.setPanelVisible(true); - - mOverlayPanelViewController.animateCollapsePanel(); - - verify(mOverlayViewGlobalStateController).setWindowFocusable(false); - } - @Test public void animateExpandPanel_shouldNotAnimateExpandPanel_doesNotExpand() { mOverlayPanelViewController.inflate(mBaseLayout); @@ -362,14 +352,6 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { assertThat(mOverlayPanelViewController.getLayout().getVisibility()).isEqualTo(View.VISIBLE); } - @Test - public void setPanelVisible_setTrue_setWindowFocusable() { - mOverlayPanelViewController.inflate(mBaseLayout); - mOverlayPanelViewController.setPanelVisible(true); - - verify(mOverlayViewGlobalStateController).setWindowFocusable(true); - } - @Test public void setPanelVisible_setFalse_windowVisible_setsWindowNotVisible() { mOverlayPanelViewController.inflate(mBaseLayout); @@ -401,15 +383,6 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { View.INVISIBLE); } - @Test - public void setPanelVisible_setFalse_setWindowNotFocusable() { - mOverlayPanelViewController.inflate(mBaseLayout); - - mOverlayPanelViewController.setPanelVisible(false); - - verify(mOverlayViewGlobalStateController).setWindowFocusable(false); - } - @Test public void dragOpenTouchListener_isNotInflated_inflatesView() { when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java index c24a3b52e348a6f5dcb1e3c5964846e0bbb82368..e784761f6d5db34fd5674d5d17bf7db07b897ea7 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.tests.R; import org.junit.Before; @@ -39,6 +40,7 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java index cba42e5a9be437e28d191026b1d82ecf85965104..294aa0d3cf9bccdc6ef4c521994a9033b34ab378 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java @@ -16,9 +16,14 @@ package com.android.systemui.car.window; +import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -28,22 +33,23 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; +import android.view.WindowInsetsController; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.car.navigationbar.CarNavigationBarController; +import com.android.systemui.car.CarSystemUiTest; import com.android.systemui.tests.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.Arrays; +@CarSystemUiTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest @@ -55,8 +61,6 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { private OverlayViewGlobalStateController mOverlayViewGlobalStateController; private ViewGroup mBaseLayout; - @Mock - private CarNavigationBarController mCarNavigationBarController; @Mock private SystemUIOverlayWindowController mSystemUIOverlayWindowController; @Mock @@ -69,18 +73,22 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { private OverlayPanelViewController mOverlayPanelViewController; @Mock private Runnable mRunnable; + @Mock + private WindowInsetsController mWindowInsetsController; @Before public void setUp() { MockitoAnnotations.initMocks(/* testClass= */ this); - mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate( - R.layout.overlay_view_global_state_controller_test, /* root= */ null); + mBaseLayout = spy((ViewGroup) LayoutInflater.from(mContext).inflate( + R.layout.overlay_view_global_state_controller_test, /* root= */ null)); + + when(mBaseLayout.getWindowInsetsController()).thenReturn(mWindowInsetsController); when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); mOverlayViewGlobalStateController = new OverlayViewGlobalStateController( - mCarNavigationBarController, mSystemUIOverlayWindowController); + mSystemUIOverlayWindowController); verify(mSystemUIOverlayWindowController).attach(); } @@ -99,24 +107,102 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { verify(mOverlayViewMediator).setupOverlayContentViewControllers(); } + @Test + public void showView_nothingVisible_windowNotFocusable_shouldShowNavBar_navBarsVisible() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void showView_nothingVisible_windowNotFocusable_shouldHideNavBar_notHidden() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController, never()).hide(navigationBars()); + } + + @Test + public void showView_nothingVisible_windowNotFocusable_shouldShowStatusBar_statusBarsVisible() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void showView_nothingVisible_windowNotFocusable_shouldHideStatusBar_notHidden() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(false); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController, never()).hide(statusBars()); + } + @Test public void showView_nothingAlreadyShown_shouldShowNavBarFalse_navigationBarsHidden() { setupOverlayViewController1(); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).hideBars(); + verify(mWindowInsetsController).hide(navigationBars()); } @Test public void showView_nothingAlreadyShown_shouldShowNavBarTrue_navigationBarsShown() { setupOverlayViewController1(); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void showView_nothingAlreadyShown_shouldShowStatusBarFalse_statusBarsHidden() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).hide(statusBars()); + } + + @Test + public void showView_nothingAlreadyShown_shouldShowStatusBarTrue_statusBarsShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void showView_nothingAlreadyShown_fitsNavBarInsets_insetsAdjusted() { + setupOverlayViewController1(); + when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(navigationBars()); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars()); } @Test @@ -163,25 +249,73 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Test public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { setupOverlayViewController1(); - setOverlayViewControllerAsShowing(mOverlayViewController1); setupOverlayViewController2(); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController).hideBars(); + verify(mWindowInsetsController).hide(navigationBars()); } @Test public void showView_newHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() { setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void showView_newHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false); + reset(mWindowInsetsController); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); + + verify(mWindowInsetsController).hide(statusBars()); + } + + @Test + public void showView_newHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void showView_newHighestZOrder_fitsNavBarInsets_insetsAdjusted() { + setupOverlayViewController1(); + when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars()); setOverlayViewControllerAsShowing(mOverlayViewController1); setupOverlayViewController2(); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars()); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars()); } @Test @@ -211,25 +345,71 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Test public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).hideBars(); + verify(mWindowInsetsController).hide(navigationBars()); } @Test public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() { + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void showView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() { + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false); + reset(mWindowInsetsController); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).hide(statusBars()); + } + + @Test + public void showView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() { + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void showView_oldHighestZOrder_fitsNavBarInsets_insetsAdjusted() { setupOverlayViewController2(); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars()); + when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars()); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars()); } @Test @@ -396,27 +576,79 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Test public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { setupOverlayViewController1(); - setOverlayViewControllerAsShowing(mOverlayViewController1); setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController).hideBars(); + verify(mWindowInsetsController).hide(navigationBars()); } @Test public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); setOverlayViewControllerAsShowing(mOverlayViewController1); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); + reset(mWindowInsetsController); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void hideView_newHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() { + setupOverlayViewController1(); setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); + reset(mWindowInsetsController); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); + + verify(mWindowInsetsController).hide(statusBars()); + } + + @Test + public void hideView_newHighestZOrder_shouldShowStatusBarTrue_statusBarShown() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void hideView_newHighestZOrder_fitsNavBarInsets_insetsAdjusted() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(navigationBars()); + when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(statusBars()); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); + + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars()); } @Test @@ -435,27 +667,77 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Test public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { setupOverlayViewController1(); - setOverlayViewControllerAsShowing(mOverlayViewController1); setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false); + reset(mWindowInsetsController); mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).hideBars(); + verify(mWindowInsetsController).hide(navigationBars()); } @Test public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void hideView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false); + reset(mWindowInsetsController); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).hide(statusBars()); + } + + @Test + public void hideView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarShown() { + setupOverlayViewController1(); + setupOverlayViewController2(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void hideView_oldHighestZOrder_fitsNavBarInsets_insetsAdjusted() { setupOverlayViewController1(); setOverlayViewControllerAsShowing(mOverlayViewController1); setupOverlayViewController2(); setOverlayViewControllerAsShowing(mOverlayViewController2); - when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController1.getInsetTypesToFit()).thenReturn(statusBars()); + when(mOverlayViewController2.getInsetTypesToFit()).thenReturn(navigationBars()); mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(navigationBars()); } @Test @@ -472,12 +754,34 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Test public void hideView_viewControllerOnlyShown_navigationBarShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(navigationBars()); + } + + @Test + public void hideView_viewControllerOnlyShown_statusBarShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mWindowInsetsController).show(statusBars()); + } + + @Test + public void hideView_viewControllerOnlyShown_insetsAdjustedToDefault() { setupOverlayViewController1(); setOverlayViewControllerAsShowing(mOverlayViewController1); mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController).showBars(); + verify(mSystemUIOverlayWindowController).setFitInsetsTypes(statusBars()); } @Test @@ -613,7 +917,7 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) { mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null); - Mockito.reset(mCarNavigationBarController, mSystemUIOverlayWindowController); + reset(mSystemUIOverlayWindowController); when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); } } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java new file mode 100644 index 0000000000000000000000000000000000000000..da7cb8e4f6ac8b1d119996084afc46b6e13455ee --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/BarControlPolicyTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; + +import static com.google.common.truth.Truth.assertThat; + +import android.car.settings.CarSettings; +import android.provider.Settings; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class BarControlPolicyTest extends SysuiTestCase { + + private static final String PACKAGE_NAME = "sample.app"; + + @Before + public void setUp() { + BarControlPolicy.reset(); + } + + @After + public void tearDown() { + Settings.Global.clearProviderForTest(); + } + + @Test + public void reloadFromSetting_notSet_doesNotSetFilters() { + BarControlPolicy.reloadFromSetting(mContext); + + assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull(); + } + + @Test + public void reloadFromSetting_invalidPolicyControlString_doesNotSetFilters() { + String text = "sample text"; + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + text + ); + + BarControlPolicy.reloadFromSetting(mContext); + + assertThat(BarControlPolicy.sImmersiveStatusFilter).isNull(); + } + + @Test + public void reloadFromSetting_validPolicyControlString_setsFilters() { + String text = "immersive.status=" + PACKAGE_NAME; + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + text + ); + + BarControlPolicy.reloadFromSetting(mContext); + + assertThat(BarControlPolicy.sImmersiveStatusFilter).isNotNull(); + } + + @Test + public void reloadFromSetting_filtersSet_doesNotSetFiltersAgain() { + String text = "immersive.status=" + PACKAGE_NAME; + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + text + ); + + BarControlPolicy.reloadFromSetting(mContext); + + assertThat(BarControlPolicy.reloadFromSetting(mContext)).isFalse(); + } + + @Test + public void getBarVisibilities_policyControlNotSet_showsSystemBars() { + int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME); + + assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars()); + assertThat(visibilities[1]).isEqualTo(0); + } + + @Test + public void getBarVisibilities_immersiveStatusForAppAndMatchingApp_hidesStatusBar() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.status=" + PACKAGE_NAME); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME); + + assertThat(visibilities[0]).isEqualTo(navigationBars()); + assertThat(visibilities[1]).isEqualTo(statusBars()); + } + + @Test + public void getBarVisibilities_immersiveStatusForAppAndNonMatchingApp_showsSystemBars() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.status=" + PACKAGE_NAME); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app"); + + assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars()); + assertThat(visibilities[1]).isEqualTo(0); + } + + @Test + public void getBarVisibilities_immersiveStatusForAppsAndNonApp_showsSystemBars() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.status=apps"); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME); + + assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars()); + assertThat(visibilities[1]).isEqualTo(0); + } + + @Test + public void getBarVisibilities_immersiveFullForAppAndMatchingApp_hidesSystemBars() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.full=" + PACKAGE_NAME); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME); + + assertThat(visibilities[0]).isEqualTo(0); + assertThat(visibilities[1]).isEqualTo(statusBars() | navigationBars()); + } + + @Test + public void getBarVisibilities_immersiveFullForAppAndNonMatchingApp_showsSystemBars() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.full=" + PACKAGE_NAME); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities("sample2.app"); + + assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars()); + assertThat(visibilities[1]).isEqualTo(0); + } + + @Test + public void getBarVisibilities_immersiveFullForAppsAndNonApp_showsSystemBars() { + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + "immersive.full=apps"); + BarControlPolicy.reloadFromSetting(mContext); + + int[] visibilities = BarControlPolicy.getBarVisibilities(PACKAGE_NAME); + + assertThat(visibilities[0]).isEqualTo(statusBars() | navigationBars()); + assertThat(visibilities[1]).isEqualTo(0); + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..29cc8eec4bc3ed8614c4ebb27c1e07f9b95cc97e --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.wm; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; + +import android.car.settings.CarSettings; +import android.os.Handler; +import android.os.RemoteException; +import android.provider.Settings; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.IWindowManager; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.TransactionPool; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class DisplaySystemBarsControllerTest extends SysuiTestCase { + + private DisplaySystemBarsController mController; + + private static final int DISPLAY_ID = 1; + + @Mock + private SystemWindows mSystemWindows; + @Mock + private IWindowManager mIWindowManager; + @Mock + private DisplayController mDisplayController; + @Mock + private Handler mHandler; + @Mock + private TransactionPool mTransactionPool; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSystemWindows.mContext = mContext; + mSystemWindows.mWmService = mIWindowManager; + + mController = new DisplaySystemBarsController( + mSystemWindows, + mDisplayController, + mHandler, + mTransactionPool + ); + } + + @Test + public void onDisplayAdded_setsDisplayWindowInsetsControllerOnWMService() + throws RemoteException { + mController.onDisplayAdded(DISPLAY_ID); + + verify(mIWindowManager).setDisplayWindowInsetsController( + eq(DISPLAY_ID), any(DisplaySystemBarsController.PerDisplay.class)); + } + + @Test + public void onDisplayAdded_loadsBarControlPolicyFilters() { + String text = "sample text"; + Settings.Global.putString( + mContext.getContentResolver(), + CarSettings.Global.SYSTEM_BAR_VISIBILITY_OVERRIDE, + text + ); + + mController.onDisplayAdded(DISPLAY_ID); + + assertThat(BarControlPolicy.sSettingValue).isEqualTo(text); + } + + @Test + public void onDisplayRemoved_unsetsDisplayWindowInsetsControllerInWMService() + throws RemoteException { + mController.onDisplayAdded(DISPLAY_ID); + + mController.onDisplayRemoved(DISPLAY_ID); + + verify(mIWindowManager).setDisplayWindowInsetsController( + DISPLAY_ID, /* displayWindowInsetsController= */ null); + } +} diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index f42bf1982b36807a8e531b328d6a94d53d61bc12..11d1b0a9ef2a26974172d28e07bc5b021cbfcae4 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -482,6 +482,13 @@ public class ExternalStorageProvider extends FileSystemProvider { } } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml new file mode 100644 index 0000000000000000000000000000000000000000..16e91903084fb1dd446af3680fdbeaa51a590f4e --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_0.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml new file mode 100644 index 0000000000000000000000000000000000000000..4c338c9681941bca1158ba097b4bd8455fa6b66c --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_1.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml new file mode 100644 index 0000000000000000000000000000000000000000..79037dbccf2dc1ad4125bb5982566600c6cf3009 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_2.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml new file mode 100644 index 0000000000000000000000000000000000000000..21ad128f81ff5065f55515c95d51ccdcab391f9b --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_3.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml new file mode 100644 index 0000000000000000000000000000000000000000..2ec5ba30cdc374a1b25d49aa699c19312e94d4f1 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_show_x_wifi_signal_4.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index a43412e116c856d3d9294deb8b3923008d3f74e4..b2808061586be16f3959cf0d70aebb617dc6a399 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -49,11 +49,19 @@ public class Utils { private static String sSharedSystemSharedLibPackageName; static final int[] WIFI_PIE = { - com.android.internal.R.drawable.ic_wifi_signal_0, - com.android.internal.R.drawable.ic_wifi_signal_1, - com.android.internal.R.drawable.ic_wifi_signal_2, - com.android.internal.R.drawable.ic_wifi_signal_3, - com.android.internal.R.drawable.ic_wifi_signal_4 + com.android.internal.R.drawable.ic_wifi_signal_0, + com.android.internal.R.drawable.ic_wifi_signal_1, + com.android.internal.R.drawable.ic_wifi_signal_2, + com.android.internal.R.drawable.ic_wifi_signal_3, + com.android.internal.R.drawable.ic_wifi_signal_4 + }; + + static final int[] SHOW_X_WIFI_PIE = { + R.drawable.ic_show_x_wifi_signal_0, + R.drawable.ic_show_x_wifi_signal_1, + R.drawable.ic_show_x_wifi_signal_2, + R.drawable.ic_show_x_wifi_signal_3, + R.drawable.ic_show_x_wifi_signal_4 }; public static void updateLocationEnabled(Context context, boolean enabled, int userId, @@ -353,10 +361,22 @@ public class Utils { * @throws IllegalArgumentException if an invalid RSSI level is given. */ public static int getWifiIconResource(int level) { + return getWifiIconResource(false /* showX */, level); + } + + /** + * Returns the Wifi icon resource for a given RSSI level. + * + * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x + * signal icon to users. + * @param level The number of bars to show (0-4) + * @throws IllegalArgumentException if an invalid RSSI level is given. + */ + public static int getWifiIconResource(boolean showX, int level) { if (level < 0 || level >= WIFI_PIE.length) { throw new IllegalArgumentException("No Wifi icon found for level: " + level); } - return WIFI_PIE[level]; + return showX ? SHOW_X_WIFI_PIE[level] : WIFI_PIE[level]; } public static int getDefaultStorageManagerDaysToRetain(Resources resources) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 9d06c8467e41a49be89e7d73c4276e4421205adf..72a6074ff89c3b61ae0d801e944e8f5fa499c925 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -465,7 +465,16 @@ public class LocalMediaManager implements BluetoothCallback { synchronized (mMediaDevicesLock) { mMediaDevices.clear(); mMediaDevices.addAll(devices); - mMediaDevices.addAll(buildDisconnectedBluetoothDevice()); + // Add disconnected bluetooth devices only when phone output device is available. + for (MediaDevice device : devices) { + final int type = device.getDeviceType(); + if (type == MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE + || type == MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE + || type == MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE) { + mMediaDevices.addAll(buildDisconnectedBluetoothDevice()); + break; + } + } } final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice(); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java index a53bc9f966d2b0fd129221d91295364e119ee6f2..aad0d3af662616b7d0f05299a392c41920df0174 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiEntryPreference.java @@ -64,6 +64,7 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt private final IconInjector mIconInjector; private WifiEntry mWifiEntry; private int mLevel = -1; + private boolean mShowX; // Shows the Wi-Fi signl icon of Pie+x when it's true. private CharSequence mContentDescription; private OnButtonClickListener mOnButtonClickListener; @@ -136,9 +137,11 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt public void refresh() { setTitle(mWifiEntry.getTitle()); final int level = mWifiEntry.getLevel(); - if (level != mLevel) { + final boolean showX = mWifiEntry.shouldShowXLevelIcon(); + if (level != mLevel || showX != mShowX) { mLevel = level; - updateIcon(mLevel); + mShowX = showX; + updateIcon(mShowX, mLevel); notifyChanged(); } @@ -184,13 +187,13 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt } - private void updateIcon(int level) { + private void updateIcon(boolean showX, int level) { if (level == -1) { setIcon(null); return; } - final Drawable drawable = mIconInjector.getIcon(level); + final Drawable drawable = mIconInjector.getIcon(showX, level); if (drawable != null) { drawable.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorControlNormal)); @@ -260,8 +263,8 @@ public class WifiEntryPreference extends Preference implements WifiEntry.WifiEnt mContext = context; } - public Drawable getIcon(int level) { - return mContext.getDrawable(Utils.getWifiIconResource(level)); + public Drawable getIcon(boolean showX, int level) { + return mContext.getDrawable(Utils.getWifiIconResource(showX, level)); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index b7ae3dca5c166e40ae5216670abc5995bdde345c..c57d4ad962bde3be98f9841b83b14a7c6dc9cc01 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -13,6 +13,7 @@ package com.android.settingslib.wifi; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import android.content.Context; import android.content.Intent; @@ -189,10 +190,12 @@ public class WifiStatusTracker { } } updateStatusLabel(); + mCallback.run(); } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) { // Default to -200 as its below WifiManager.MIN_RSSI. updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200)); updateStatusLabel(); + mCallback.run(); } } @@ -218,13 +221,15 @@ public class WifiStatusTracker { return; } NetworkCapabilities networkCapabilities; - final Network currentWifiNetwork = mWifiManager.getCurrentNetwork(); - if (currentWifiNetwork != null && currentWifiNetwork.equals(mDefaultNetwork)) { + isDefaultNetwork = false; + if (mDefaultNetworkCapabilities != null) { + isDefaultNetwork = mDefaultNetworkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_WIFI); + } + if (isDefaultNetwork) { // Wifi is connected and the default network. - isDefaultNetwork = true; networkCapabilities = mDefaultNetworkCapabilities; } else { - isDefaultNetwork = false; networkCapabilities = mConnectivityManager.getNetworkCapabilities( mWifiManager.getCurrentNetwork()); } @@ -246,6 +251,10 @@ public class WifiStatusTracker { statusLabel = mContext.getString(R.string.wifi_status_no_internet); } return; + } else if (!isDefaultNetwork && mDefaultNetworkCapabilities != null + && mDefaultNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + statusLabel = mContext.getString(R.string.wifi_connected_low_quality); + return; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index a654fd47ea1297ef30f0890ec6e5c2bf5644506f..8e850b25159c25d32b51ad7e50b894e62cf7ea2d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -585,6 +585,7 @@ public class LocalMediaManagerTest { when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); when(device3.getId()).thenReturn(TEST_DEVICE_ID_3); + when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE); when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id"); assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); @@ -683,6 +684,7 @@ public class LocalMediaManagerTest { when(device1.getId()).thenReturn(TEST_DEVICE_ID_1); when(device2.getId()).thenReturn(TEST_DEVICE_ID_2); when(device3.getId()).thenReturn(TEST_DEVICE_ID_3); + when(device1.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE); when(mLocalMediaManager.mPhoneDevice.getId()).thenReturn("test_phone_id"); assertThat(mLocalMediaManager.mMediaDevices).hasSize(2); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java index 46e699d3bed5fd88426ad206d0f9fd947845e8b2..c21830b28e3ae25ce32c51a250fbd016b30a57c2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiEntryPreferenceTest.java @@ -62,6 +62,17 @@ public class WifiEntryPreferenceTest { @Mock private Drawable mMockDrawable4; + @Mock + private Drawable mMockShowXDrawable0; + @Mock + private Drawable mMockShowXDrawable1; + @Mock + private Drawable mMockShowXDrawable2; + @Mock + private Drawable mMockShowXDrawable3; + @Mock + private Drawable mMockShowXDrawable4; + private static final String MOCK_TITLE = "title"; private static final String MOCK_SUMMARY = "summary"; private static final String FAKE_URI_STRING = "fakeuri"; @@ -75,11 +86,22 @@ public class WifiEntryPreferenceTest { when(mMockWifiEntry.getTitle()).thenReturn(MOCK_TITLE); when(mMockWifiEntry.getSummary(false /* concise */)).thenReturn(MOCK_SUMMARY); - when(mMockIconInjector.getIcon(0)).thenReturn(mMockDrawable0); - when(mMockIconInjector.getIcon(1)).thenReturn(mMockDrawable1); - when(mMockIconInjector.getIcon(2)).thenReturn(mMockDrawable2); - when(mMockIconInjector.getIcon(3)).thenReturn(mMockDrawable3); - when(mMockIconInjector.getIcon(4)).thenReturn(mMockDrawable4); + when(mMockIconInjector.getIcon(false /* showX */, 0)).thenReturn(mMockDrawable0); + when(mMockIconInjector.getIcon(false /* showX */, 1)).thenReturn(mMockDrawable1); + when(mMockIconInjector.getIcon(false /* showX */, 2)).thenReturn(mMockDrawable2); + when(mMockIconInjector.getIcon(false /* showX */, 3)).thenReturn(mMockDrawable3); + when(mMockIconInjector.getIcon(false /* showX */, 4)).thenReturn(mMockDrawable4); + + when(mMockIconInjector.getIcon(true /* showX */, 0)) + .thenReturn(mMockShowXDrawable0); + when(mMockIconInjector.getIcon(true /* showX */, 1)) + .thenReturn(mMockShowXDrawable1); + when(mMockIconInjector.getIcon(true /* showX */, 2)) + .thenReturn(mMockShowXDrawable2); + when(mMockIconInjector.getIcon(true /* showX */, 3)) + .thenReturn(mMockShowXDrawable3); + when(mMockIconInjector.getIcon(true /* showX */, 4)) + .thenReturn(mMockShowXDrawable4); } @Test @@ -154,6 +176,36 @@ public class WifiEntryPreferenceTest { mMockDrawable2, mMockDrawable3, mMockDrawable4, null); } + @Test + public void levelChanged_showXWifiRefresh_shouldUpdateLevelIcon() { + final List iconList = new ArrayList<>(); + when(mMockWifiEntry.shouldShowXLevelIcon()).thenReturn(true); + final WifiEntryPreference pref = + new WifiEntryPreference(mContext, mMockWifiEntry, mMockIconInjector); + + when(mMockWifiEntry.getLevel()).thenReturn(0); + pref.refresh(); + iconList.add(pref.getIcon()); + when(mMockWifiEntry.getLevel()).thenReturn(1); + pref.refresh(); + iconList.add(pref.getIcon()); + when(mMockWifiEntry.getLevel()).thenReturn(2); + pref.refresh(); + iconList.add(pref.getIcon()); + when(mMockWifiEntry.getLevel()).thenReturn(3); + pref.refresh(); + iconList.add(pref.getIcon()); + when(mMockWifiEntry.getLevel()).thenReturn(4); + pref.refresh(); + iconList.add(pref.getIcon()); + when(mMockWifiEntry.getLevel()).thenReturn(-1); + pref.refresh(); + iconList.add(pref.getIcon()); + + assertThat(iconList).containsExactly(mMockShowXDrawable0, mMockShowXDrawable1, + mMockShowXDrawable2, mMockShowXDrawable3, mMockShowXDrawable4, null); + } + @Test public void notNull_whenGetHelpUriString_shouldSetImageButtonVisible() { when(mMockWifiEntry.getHelpUriString()).thenReturn(FAKE_URI_STRING); diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index d05e6e16bc1a1cd664fb7929835bf75640afa349..3055104714a1daaafb7cbfa5d24457f44c429b64 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -166,6 +166,9 @@ public class SecureSettings { Settings.Secure.PEOPLE_STRIP, Settings.Secure.MEDIA_CONTROLS_RESUME, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, - Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, + Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED, + Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS, + Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index fa810bdf3a4e7ca63dc0e3564902ad2b78626ab3..f1846db9d7b5e281715b75ecad957a1b913a9e8e 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -251,5 +251,9 @@ public class SecureSettingsValidators { VALIDATORS.put( Secure.ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); + VALIDATORS.put(Secure.ADAPTIVE_CONNECTIVITY_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put( + Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS, NONE_NEGATIVE_LONG_VALIDATOR); + VALIDATORS.put(Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 7c198c88d5b61f9344618fc2198d00a7bb19a69e..89a55e42db536bee4205cd90e1cf80f9403daa4c 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -773,29 +773,29 @@ class SettingsProtoDumpUtil { Settings.Global.GPU_DEBUG_LAYERS_GLES, GlobalSettingsProto.Gpu.DEBUG_LAYERS_GLES); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_ALL_APPS, - GlobalSettingsProto.Gpu.GAME_DRIVER_ALL_APPS); + Settings.Global.UPDATABLE_DRIVER_ALL_APPS, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_ALL_APPS); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_OPT_IN_APPS, - GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_IN_APPS); + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS, - GlobalSettingsProto.Gpu.GAME_DRIVER_PRERELEASE_OPT_IN_APPS); + Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_OPT_OUT_APPS, - GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_OUT_APPS); + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_DENYLIST, - GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLIST); + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRODUCTION_DENYLIST); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_ALLOWLIST, - GlobalSettingsProto.Gpu.GAME_DRIVER_ALLOWLIST); + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_DENYLISTS, - GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLISTS); + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS); dumpSetting(s, p, - Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, - GlobalSettingsProto.Gpu.GAME_DRIVER_SPHAL_LIBRARIES); + Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES, + GlobalSettingsProto.Gpu.UPDATABLE_DRIVER_SPHAL_LIBRARIES); p.end(gpuToken); final long hdmiToken = p.start(GlobalSettingsProto.HDMI); @@ -1875,6 +1875,15 @@ class SettingsProtoDumpUtil { SecureSettingsProto.Assist.GESTURE_SETUP_COMPLETE); p.end(assistToken); + final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES); + dumpSetting(s, p, + Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS, + SecureSettingsProto.AssistHandles.LEARNING_TIME_ELAPSED_MILLIS); + dumpSetting(s, p, + Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT, + SecureSettingsProto.AssistHandles.LEARNING_EVENT_COUNT); + p.end(assistHandlesToken); + final long autofillToken = p.start(SecureSettingsProto.AUTOFILL); dumpSetting(s, p, Settings.Secure.AUTOFILL_SERVICE, @@ -1976,6 +1985,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, SecureSettingsProto.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS); + dumpSetting(s, p, + Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED, + SecureSettingsProto.ADAPTIVE_CONNECTIVITY_ENABLED); final long controlsToken = p.start(SecureSettingsProto.CONTROLS); dumpSetting(s, p, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java index 6e5b8890438d1b74ab3f98886a896bbc14bb6748..66aa7baa3b51beb12685895029aef5e2e415d5b8 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java @@ -35,19 +35,17 @@ import java.util.List; public class WriteFallbackSettingsFilesJobService extends JobService { @Override public boolean onStartJob(final JobParameters params) { - switch (params.getJobId()) { - case WRITE_FALLBACK_SETTINGS_FILES_JOB_ID: - final List settingsFiles = new ArrayList<>(); - settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, "")); - settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, "")); - settingsFiles.add(params.getExtras().getString(TABLE_SECURE, "")); - settingsFiles.add(params.getExtras().getString(TABLE_SSAID, "")); - settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, "")); - SettingsProvider.writeFallBackSettingsFiles(settingsFiles); - return true; - default: - return false; + if (params.getJobId() != WRITE_FALLBACK_SETTINGS_FILES_JOB_ID) { + return false; } + final List settingsFiles = new ArrayList<>(); + settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, "")); + settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, "")); + settingsFiles.add(params.getExtras().getString(TABLE_SECURE, "")); + settingsFiles.add(params.getExtras().getString(TABLE_SSAID, "")); + settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, "")); + SettingsProvider.writeFallBackSettingsFiles(settingsFiles); + return false; } @Override diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index bc1c3f9080972508bcd4c71093616aa07b12da17..e90bb36214a823d664ab83bb40ec9614af0fe66b 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -503,14 +503,14 @@ public class SettingsBackupTest { Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES, Settings.Global.GLOBAL_SETTINGS_ANGLE_ALLOWLIST, - Settings.Global.GAME_DRIVER_ALL_APPS, - Settings.Global.GAME_DRIVER_OPT_IN_APPS, - Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS, - Settings.Global.GAME_DRIVER_OPT_OUT_APPS, - Settings.Global.GAME_DRIVER_DENYLISTS, - Settings.Global.GAME_DRIVER_DENYLIST, - Settings.Global.GAME_DRIVER_ALLOWLIST, - Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, + Settings.Global.UPDATABLE_DRIVER_ALL_APPS, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS, + Settings.Global.UPDATABLE_DRIVER_PRERELEASE_OPT_IN_APPS, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_OUT_APPS, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLISTS, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST, + Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST, + Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES, Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX, Settings.Global.GPU_DEBUG_LAYER_APP, Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING, diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index a7ef5e6f58f0f7ab1837e3149e02e2dbed67abe9..6e74184cef0264c4d1026e87f9929171d25d3032 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -113,6 +113,7 @@ + @@ -239,6 +240,9 @@ + + + @@ -266,6 +270,7 @@ + @@ -395,19 +400,15 @@ - - - - - - @@ -720,10 +721,9 @@ - + - - - - - - - + + + + + + - - - - - - + + + + + - + \ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml index 3018a022e763f853848aa7876f5d08c1fdb4a9d1..370576b4346323403a58b41808493b2258ff620c 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml @@ -33,6 +33,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/Keyguard.TextView" + android:layout_marginBottom="8dp" android:singleLine="true" android:ellipsize="marquee" android:visibility="gone" @@ -42,11 +43,9 @@ + style="@style/Keyguard.TextView.EmergencyButton" /> diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 5f2a946a1b6d8b374df68ac7a4ff04a29ba90532..401f3e3e0685fe9e51e6192ab75d89583398ed51 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -23,10 +23,13 @@ ?attr/wallpaperTextColorSecondary @dimen/kg_status_line_font_size -