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
-