diff --git a/Android.bp b/Android.bp index 939c2417a627c..da4b8fca8d44b 100644 --- a/Android.bp +++ b/Android.bp @@ -142,6 +142,7 @@ filegroup { ":deviceproductinfoconstants_aidl", ":adbrootservice_aidl", + ":lmofreeform_aidl", // For the generated R.java and Manifest.java ":framework-res{.aapt.srcjar}", diff --git a/CleanSpec.mk b/CleanSpec.mk index 87535b3991ecc..d5fef59532550 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -78,6 +78,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libhwui.so) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwui.so) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/storage/*) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/IClipboard.P) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/pocket/*) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/android/internal/telephony/ITelephonyRegistry.P) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/docs/api-stubs*) diff --git a/SystemUI/shared/src/com/android/systemui/shared/system/FullscreenTaskStackChangeListener.kt b/SystemUI/shared/src/com/android/systemui/shared/system/FullscreenTaskStackChangeListener.kt new file mode 100644 index 0000000000000..081d051770b95 --- /dev/null +++ b/SystemUI/shared/src/com/android/systemui/shared/system/FullscreenTaskStackChangeListener.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.systemui.shared.system + +import android.app.ActivityTaskManager +import android.app.ActivityTaskManager.INVALID_TASK_ID +import android.app.IActivityTaskManager +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.content.Context +import android.os.RemoteException +import android.util.Log + +/** + * TaskStackChangeListener that ignores freeform / mini-window focuses change +*/ +open class FullscreenTaskStackChangeListener( + private val context: Context, + private val observeActivityChange: Boolean = false +) : TaskStackChangeListener { + + var debug = false + var debugTag = DEFAULT_TAG + + private val iActivityTaskManager by lazy { ActivityTaskManager.getService() } + + var topPackageName = String() + private set + var topActivityName = String() + private set + var topTaskId = INVALID_TASK_ID + private set + + private fun handleChange(newPackageName: String, newActivityName: String, newTaskId: Int) { + if (topPackageName == newPackageName && topActivityName == newActivityName) { + return + } + topActivityName = newActivityName + if (!observeActivityChange && topPackageName == newPackageName) { + return + } + topPackageName = newPackageName + topTaskId = newTaskId + if (debug) { + Log.d(debugTag, "Change: mTopPackage=$topPackageName" + + ", mTopActivity=$topActivityName" + + ", mTopTaskId=$topTaskId") + } + onFullscreenTaskChanged(topPackageName, topActivityName, topTaskId) + } + + override fun onTaskStackChanged() { + forceCheck() + } + + override fun onTaskFocusChanged(taskId: Int, focused: Boolean) { + if (focused) { + forceCheck() + } + } + + fun forceCheck() { + try { + iActivityTaskManager.focusedRootTaskInfo?.let { info -> + info.windowingMode.let { + if (it == WINDOWING_MODE_FREEFORM) { + return + } + } + info.topActivity?.let { + handleChange(it.packageName, it.className, info.taskId) + } + } + } catch (e: RemoteException) {} + } + + open fun onFullscreenTaskChanged(packageName: String, activityName: String, taskId: Int) {} + + companion object { + private const val DEFAULT_TAG = "FullscreenTaskStackChangeListener" + } +} diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java index ec6a8b8af8992..c48184498e244 100644 --- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java +++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java @@ -1049,6 +1049,16 @@ private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMilli long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener, String listenerTag, Executor targetExecutor, WorkSource workSource, AlarmClockInfo alarmClock) { + + if (mPackageName.equals("com.google.android.gms") + || mPackageName.equals("com.google.android.keep") + || mPackageName.equals("com.google.android.deskclock") + || mPackageName.equals("com.android.deskclock")) { + if (windowMillis == WINDOW_EXACT && !canScheduleExactAlarms()) { + windowMillis = WINDOW_HEURISTIC; + } + } + if (triggerAtMillis < 0) { /* NOTYET if (mAlwaysExact) { diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index 0b286a7bf8de4..cda18f1ffb97a 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -3241,9 +3241,11 @@ public int[] getAppIdTempWhitelistInternal() { void addPowerSaveTempAllowlistAppChecked(String packageName, long duration, int userId, @ReasonCode int reasonCode, @Nullable String reason) throws RemoteException { - getContext().enforceCallingOrSelfPermission( - Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, - "No permission to change device idle whitelist"); + if (!packageName.equals("com.google.android.gms")) { + getContext().enforceCallingOrSelfPermission( + Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, + "No permission to change device idle whitelist"); + } final int callingUid = Binder.getCallingUid(); userId = ActivityManager.getService().handleIncomingUser( Binder.getCallingPid(), diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java index 03bf2fede2a27..12173bcead676 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -96,24 +96,7 @@ class JobConcurrencyManager { static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_"; private static final String KEY_CONCURRENCY_LIMIT = CONFIG_KEY_PREFIX_CONCURRENCY + "limit"; - static final int DEFAULT_CONCURRENCY_LIMIT; - - static { - if (ActivityManager.isLowRamDeviceStatic()) { - DEFAULT_CONCURRENCY_LIMIT = 8; - } else { - final long ramBytes = new MemInfoReader().getTotalSize(); - if (ramBytes <= GIGABYTES.toBytes(6)) { - DEFAULT_CONCURRENCY_LIMIT = 16; - } else if (ramBytes <= GIGABYTES.toBytes(8)) { - DEFAULT_CONCURRENCY_LIMIT = 20; - } else if (ramBytes <= GIGABYTES.toBytes(12)) { - DEFAULT_CONCURRENCY_LIMIT = 32; - } else { - DEFAULT_CONCURRENCY_LIMIT = 40; - } - } - } + static final int DEFAULT_CONCURRENCY_LIMIT = 8; private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS = CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms"; diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java index 9d4cba18b4b15..9220008e2a2fc 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java @@ -157,6 +157,7 @@ private String getServiceProcessLocked(JobStatus jobStatus) { } ServiceInfo si; + boolean jobCleared = false; try { // createContextAsUser may potentially be expensive // TODO: cache user context or improve ContextImpl implementation if this becomes @@ -168,12 +169,16 @@ private String getServiceProcessLocked(JobStatus jobStatus) { if (mService.areUsersStartedLocked(jobStatus)) { // User is fully unlocked but PM still says the package doesn't exist. Slog.e(TAG, "Job exists for non-existent package: " + service.getPackageName()); + mService.getJobStore().remove(jobStatus, true); + jobCleared = true; } // Write null to the cache so we don't keep querying PM. si = null; } final String processName = si == null ? null : si.processName; - mServiceProcessCache.add(userId, service, processName); + if (!jobCleared) { + mServiceProcessCache.add(userId, service, processName); + } return processName; } 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 56d81b182a505..a15bca89969c3 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -2691,9 +2691,7 @@ void onBootPhase(int phase) { final ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - if (activityManager.isLowRamDevice() || ActivityManager.isSmallBatteryDevice()) { - mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; - } + mAutoRestrictedBucketDelayMs = 12 * ONE_HOUR; } else if (phase == PHASE_BOOT_COMPLETED) { // mWellbeingApp needs to be initialized lazily after boot to allow for roles to be // parsed and the wellbeing role-holder to be assigned diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 0a057461228c7..33131f6acfff9 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -239,7 +239,7 @@ class BootAnimation : public Thread, public IBinder::DeathRecipient int mTargetInset; bool mUseNpotTextures = false; EGLDisplay mEgl; - EGLDisplay mEglContext; + EGLContext mEglContext; // Per-Display Attributes (to support multi-display) std::vector mDisplays; bool mClockEnabled; diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index fef97d382da16..ef709c094dd66 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -739,7 +739,7 @@ void callOnList( for (int i = 0; i < size; i++) { //noinspection unchecked T item = (T) array[i]; - call.call(item, animator, isReverse); + if (item != null) call.call(item, animator, isReverse); array[i] = null; } // Store it for the next call so we can reuse this array, if needed. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6777dbaad9b90..f826964b4fc62 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -191,6 +191,8 @@ import android.se.omapi.SeServiceManager; import android.security.NetworkSecurityPolicy; import android.security.net.config.NetworkSecurityConfigProvider; +import android.security.gameprops.GamePropsSpoofService; +import android.security.pif.PlayIntegritySpoofService; import android.system.ErrnoException; import android.telephony.TelephonyFrameworkInitializer; import android.util.AndroidRuntimeException; @@ -209,6 +211,7 @@ import android.util.UtilConfig; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; +import android.view.animation.AnimationUtils; import android.view.Display; import android.view.SurfaceControl; import android.view.ThreadedRenderer; @@ -4724,7 +4727,7 @@ private void reportSizeConfigurations(ActivityClientRecord r) { return; } Configuration[] configurations = r.activity.getResources().getSizeConfigurations(); - if (configurations == null) { + if (configurations == null || r.activity.mFinished) { return; } r.mSizeConfigurations = new SizeConfigurationBuckets(configurations); @@ -5571,7 +5574,7 @@ private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (DEBUG_SERVICE) Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind); - if (s != null) { + if (s != null && createData != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(isProtectedComponent(createData.info), @@ -5602,7 +5605,7 @@ private void handleBindService(BindServiceData data) { private void handleUnbindService(BindServiceData data) { CreateServiceData createData = mServicesData.get(data.token); Service s = mServices.get(data.token); - if (s != null) { + if (s != null && createData != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(isProtectedComponent(createData.info), @@ -5710,7 +5713,7 @@ private void handleDumpProvider(DumpComponentInfo info) { private void handleServiceArgs(ServiceArgsData data) { CreateServiceData createData = mServicesData.get(data.token); Service s = mServices.get(data.token); - if (s != null) { + if (s != null && createData != null) { try { if (data.args != null) { data.args.setExtrasClassLoader(s.getClassLoader()); @@ -7935,6 +7938,9 @@ private void handleBindApplication(AppBindData data) { data.info = getPackageInfo(data.appInfo, mCompatibilityInfo, null /* baseLoader */, false /* securityViolation */, true /* includeCode */, false /* registerPackage */, isSdkSandbox); + + Typeface.changeFont(); + if (isSdkSandbox) { data.info.setSdkSandboxStorage(data.sdkSandboxClientAppVolumeUuid, data.sdkSandboxClientAppPackage); @@ -8008,6 +8014,16 @@ private void handleBindApplication(AppBindData data) { final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); mConfigurationController.updateLocaleListFromAppContext(appContext); + GamePropsSpoofService.getInstance().spoofForPackage(data.appInfo.packageName, appContext); + + PlayIntegritySpoofService pifService = PlayIntegritySpoofService.getInstance(); + if (pifService.shouldSpoof(data.processName)) { + pifService.spoofBuildFields(data.processName); + if (pifService.isSpoofSignatureEnabled()) { + pifService.spoofSignature(); + } + } + // Initialize the default http proxy in this process. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Setup proxies"); try { @@ -8174,6 +8190,16 @@ private void handleBindApplication(AppBindData data) { } } + if (!Process.isIsolated()) { + try { + if (AnimationUtils.sPerfAnimEnabled) { + AnimationUtils.ActivityAnimations.preload(); + } + } catch (Exception e) { + Slog.e(TAG, "Failed to preload animations", e); + } + } + try { mgr.finishAttachApplication(mStartSeq, timestampApplicationOnCreateNs); } catch (RemoteException ex) { @@ -9067,7 +9093,9 @@ private void attach(boolean system, long startSeq) { RuntimeInit.setApplicationObject(mAppThread.asBinder()); final IActivityManager mgr = ActivityManager.getService(); try { - mgr.attachApplication(mAppThread, startSeq); + if (mgr != null) { + mgr.attachApplication(mAppThread, startSeq); + } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } @@ -9085,8 +9113,11 @@ private void attach(boolean system, long startSeq) { + " total=" + (runtime.totalMemory()/1024) + " used=" + (dalvikUsed/1024)); mSomeActivitiesChanged = false; + final IActivityTaskManager atmgr = ActivityTaskManager.getService(); try { - ActivityTaskManager.getService().releaseSomeActivities(mAppThread); + if (atmgr != null) { + atmgr.releaseSomeActivities(mAppThread); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 71477f5ac9820..2c38de7a837a6 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -30,6 +30,7 @@ import static android.content.pm.Checksum.TYPE_WHOLE_SHA256; import static android.content.pm.Checksum.TYPE_WHOLE_SHA512; +import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.DrawableRes; import android.annotation.NonNull; @@ -206,6 +207,12 @@ public class ApplicationPackageManager extends PackageManager { private final boolean mUseSystemFeaturesCache; + // Spoof setting caches — refreshed by ContentObserver, avoids per-call Settings reads + private static volatile boolean sTensorGlobalEnabled = false; + private static volatile Set sTensorTargets = null; + private static volatile boolean sPhotosSpoofEnabled = true; + private static boolean sSpoofObserverRegistered = false; + UserManager getUserManager() { if (mUserManager == null) { mUserManager = UserManager.get(mContext); @@ -791,12 +798,37 @@ public FeatureInfo[] getSystemAvailableFeatures() { if (parceledList == null) { return new FeatureInfo[0]; } - final List list = parceledList.getList(); - final FeatureInfo[] res = new FeatureInfo[list.size()]; - for (int i = 0; i < res.length; i++) { - res[i] = list.get(i); + final List list = new ArrayList<>(parceledList.getList()); + + // Inject Tensor features when toggle is enabled + final String callingPkg = ActivityThread.currentPackageName(); + final Set targets = sTensorTargets; + final boolean forceTensor = !IS_TENSOR_DEVICE + && sTensorGlobalEnabled + && callingPkg != null + && targets != null + && targets.contains(callingPkg); + + if (forceTensor) { + for (String feature : FEATURES_TENSOR) { + boolean exists = false; + + for (FeatureInfo fi : list) { + if (feature.equals(fi.name)) { + exists = true; + break; + } + } + + if (!exists) { + FeatureInfo fi = new FeatureInfo(); + fi.name = feature; + fi.version = 0; + list.add(fi); + } + } } - return res; + return list.toArray(new FeatureInfo[0]); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -837,8 +869,133 @@ public Boolean recompute(HasSystemFeatureQuery query) { } }; + private static final ArraySet PRIV_PKGS = new ArraySet<>(); + private static final ArraySet FEATURES_PIXEL = new ArraySet<>(); + private static final ArraySet FEATURES_PIXEL_OTHERS = new ArraySet<>(); + private static final ArraySet FEATURES_TENSOR = new ArraySet<>(); + private static final ArraySet FEATURES_NEXUS = new ArraySet<>(); + private static final ArraySet TENSOR_CODENAMES = new ArraySet<>(); + private static final boolean IS_TENSOR_DEVICE; + + static { + Collections.addAll(FEATURES_PIXEL, + "com.google.android.apps.photos.PIXEL_2019_PRELOAD", + "com.google.android.apps.photos.PIXEL_2019_MIDYEAR_PRELOAD", + "com.google.android.apps.photos.PIXEL_2018_PRELOAD", + "com.google.android.apps.photos.PIXEL_2017_PRELOAD", + "com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2020_EXPERIENCE", + "com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2019_EXPERIENCE", + "com.google.android.feature.PIXEL_2019_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2018_EXPERIENCE", + "com.google.android.feature.PIXEL_2017_EXPERIENCE", + "com.google.android.feature.PIXEL_EXPERIENCE", + "com.google.android.feature.GOOGLE_BUILD", + "com.google.android.feature.GOOGLE_EXPERIENCE" + ); + + Collections.addAll(FEATURES_PIXEL_OTHERS, + "com.google.android.feature.ASI", + "com.google.android.feature.ANDROID_ONE_EXPERIENCE", + "com.google.android.feature.GOOGLE_FI_BUNDLED", + "com.google.android.feature.LILY_EXPERIENCE", + "com.google.android.feature.TURBO_PRELOAD", + "com.google.android.feature.WELLBEING", + "com.google.lens.feature.IMAGE_INTEGRATION", + "com.google.lens.feature.CAMERA_INTEGRATION", + "com.google.photos.trust_debug_certs", + "com.google.android.feature.AER_OPTIMIZED", + "com.google.android.feature.NEXT_GENERATION_ASSISTANT", + "android.software.game_service", + "com.google.android.feature.EXCHANGE_6_2", + "com.google.android.apps.dialer.call_recording_audio", + "com.google.android.apps.dialer.SUPPORTED" + ); + + Collections.addAll(FEATURES_TENSOR, + "com.google.android.feature.PIXEL_2026_EXPERIENCE", + "com.google.android.feature.PIXEL_2026_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2025_EXPERIENCE", + "com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2024_EXPERIENCE", + "com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2023_EXPERIENCE", + "com.google.android.feature.PIXEL_2023_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2022_EXPERIENCE", + "com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2021_EXPERIENCE" + ); + + Collections.addAll(FEATURES_NEXUS, + "com.google.android.apps.photos.NEXUS_PRELOAD", + "com.google.android.apps.photos.nexus_preload", + "com.google.android.feature.PIXEL_EXPERIENCE", + "com.google.android.feature.GOOGLE_BUILD", + "com.google.android.feature.GOOGLE_EXPERIENCE" + ); + + Collections.addAll(TENSOR_CODENAMES, + "stallion","blazer","frankel","mustang","tegu","comet","komodo","caiman","tokay", + "akita","husky","shiba","felix","tangorpro","lynx","cheetah","panther", + "bluejay","oriole","raven" + ); + + Collections.addAll(PRIV_PKGS, + "com.google.android.googlequicksearchbox", + "com.google.android.apps.photos", + "com.google.android.apps.pixel.agent", + "com.google.android.apps.pixel.creativeassistant" + ); + + final String device = SystemProperties.get("ro.evolution.device"); + IS_TENSOR_DEVICE = TENSOR_CODENAMES.contains(device); + } + @Override public boolean hasSystemFeature(String name, int version) { + final String pkg = ActivityThread.currentPackageName(); + + if (name != null && pkg != null && PRIV_PKGS.contains(pkg)) { + final boolean photosSpoof = !Process.isIsolated() + && "com.google.android.apps.photos".equals(pkg) + && sPhotosSpoofEnabled; + if (photosSpoof) { + if (FEATURES_PIXEL.contains(name)) return false; + if (FEATURES_PIXEL_OTHERS.contains(name)) return true; + if (FEATURES_TENSOR.contains(name)) return false; + if (FEATURES_NEXUS.contains(name)) return true; + } else { + if (FEATURES_PIXEL.contains(name)) return true; + if (FEATURES_PIXEL_OTHERS.contains(name)) return true; + if (FEATURES_TENSOR.contains(name)) return true; + if (FEATURES_NEXUS.contains(name)) return true; + } + } + + if (name != null && FEATURES_TENSOR.contains(name)) { + // Do not interfere with real Tensor devices + if (IS_TENSOR_DEVICE) { + return mHasSystemFeatureCache.query( + new HasSystemFeatureQuery(name, version)); + } + + // Check cached tensor targets — populated once and refreshed via ContentObserver + final Set targets = sTensorTargets; + if (sTensorGlobalEnabled + && pkg != null + && targets != null + && targets.contains(pkg)) { + return true; + } + + return mHasSystemFeatureCache.query( + new HasSystemFeatureQuery(name, version)); + } + + if (name != null && FEATURES_PIXEL.contains(name)) return true; + if (name != null && FEATURES_PIXEL_OTHERS.contains(name)) return true; + // We check for system features in the following order: // * Build time-defined system features (constant, very efficient) // * SDK-defined system features (cached at process start, very efficient) @@ -866,8 +1023,23 @@ public static void invalidateHasSystemFeatureCache() { @Override public int checkPermission(String permName, String pkgName) { - return getPermissionManager().checkPackageNamePermission(permName, pkgName, + int res = getPermissionManager().checkPackageNamePermission(permName, pkgName, mContext.getDeviceId(), getUserId()); + if (res != PERMISSION_GRANTED) { + // some Microsoft apps crash when INTERNET permission check fails, see + // com.microsoft.aad.adal.AuthenticationContext.checkInternetPermission() and + // com.microsoft.identity.client.PublicClientApplication.checkInternetPermission() + if (Manifest.permission.INTERNET.equals(permName) + // don't rely on Context.getPackageName(), may be different from process package name + && pkgName.equals(ActivityThread.currentPackageName()) + && pkgName.toLowerCase().contains("microsoft") + && pkgName.toLowerCase().contains("com.android") + && pkgName.toLowerCase().contains("google")) + { + return PERMISSION_GRANTED; + } + } + return res; } @Override @@ -2284,6 +2456,47 @@ protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; mUseSystemFeaturesCache = isSystemFeaturesCacheAvailable(); + if (!Process.isIsolated()) { + registerSpoofSettingsObserver(); + } + } + + private void registerSpoofSettingsObserver() { + synchronized (ApplicationPackageManager.class) { + if (sSpoofObserverRegistered) return; + sSpoofObserverRegistered = true; + } + final ContentResolver cr = mContext.getContentResolver(); + final Runnable refresh = () -> { + try { + sTensorGlobalEnabled = Settings.Secure.getInt( + cr, "pi_tensor_spoof", 0) == 1; + final String raw = Settings.Secure.getString(cr, "tensor_targets"); + sTensorTargets = (raw == null || raw.isEmpty()) + ? Collections.emptySet() + : new ArraySet<>(Arrays.asList(raw.split(","))); + sPhotosSpoofEnabled = Settings.Secure.getInt( + cr, Settings.Secure.PI_PHOTOS_SPOOF, 1) == 1; + } catch (Throwable t) { + // Settings provider not ready yet; cache stays at safe defaults + } + }; + try { + final android.database.ContentObserver observer = + new android.database.ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { refresh.run(); } + }; + cr.registerContentObserver( + Settings.Secure.getUriFor("pi_tensor_spoof"), false, observer); + cr.registerContentObserver( + Settings.Secure.getUriFor("tensor_targets"), false, observer); + cr.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.PI_PHOTOS_SPOOF), false, observer); + } catch (Throwable t) { + // Observer registration failed; feature will remain disabled + } + refresh.run(); } private static boolean isSystemFeaturesCacheAvailable() { @@ -2713,7 +2926,11 @@ public void setUpdateAvailable(String packageName, boolean updateAvailable) { @Override public String getInstallerPackageName(String packageName) { try { - return mPM.getInstallerPackageName(packageName); + String installer = mPM.getInstallerPackageName(packageName); + if ("com.aurora.store".equals(installer)) { + return "com.android.vending"; + } + return installer; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/AxSandboxManager.java b/core/java/android/app/AxSandboxManager.java new file mode 100644 index 0000000000000..5c3e1298cacf4 --- /dev/null +++ b/core/java/android/app/AxSandboxManager.java @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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 android.app; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; + + +import com.android.internal.app.IAppLockStateListener; +import com.android.internal.app.IAppSessionListener; +import com.android.internal.app.IAxSandboxManager; +import com.android.internal.app.IHiddenNotificationListener; +import com.android.internal.app.HiddenNotificationInfo; + +import java.util.Collections; +import java.util.List; + +/** + * @hide + */ +@SystemService(Context.AX_SANDBOX_SERVICE) +public class AxSandboxManager { + + /** @hide */ + public static final int LOCK_BEHAVIOR_ON_LEAVE = 0; + /** @hide */ + public static final int LOCK_BEHAVIOR_TIMEOUT = 1; + /** @hide */ + public static final int LOCK_BEHAVIOR_ON_SCREEN_OFF = 2; + /** @hide */ + public static final int LOCK_BEHAVIOR_ON_KILL = 3; + + /** @hide */ + public static final String SETTING_LOCK_BEHAVIOR = "sandbox_locked_app_behavior"; + /** @hide */ + public static final String SETTING_LOCK_TIMEOUT = "sandbox_locked_app_timeout"; + /** @hide */ + public static final String SETTING_SANDBOX_CONFIG = "sandbox_config"; + + /** @hide */ + public static final String EXTRA_LOCKED_PACKAGE = "LOCKED_PACKAGE"; + /** @hide */ + public static final String EXTRA_LOCKED_UID = "LOCKED_UID"; + /** @hide */ + public static final String EXTRA_LOCKED_COMPONENT = "LOCKED_COMPONENT"; + /** @hide */ + public static final String EXTRA_NOTIFICATION_APP_LOCKED = "android.app.extra.AX_APP_LOCKED"; + + /** @hide */ + public static final int DEFAULT_LOCK_TIMEOUT = 30; + + /** @hide */ + public enum AppLockState { + NONE, + UNLOCKED, + LOCKED; + + public boolean hasAppLock() { + return this != NONE; + } + + public boolean needsAuth() { + return this == LOCKED; + } + + public static AppLockState fromOrdinal(int ordinal) { + AppLockState[] values = values(); + if (ordinal < 0 || ordinal >= values.length) return NONE; + return values[ordinal]; + } + } + + private final Context mContext; + private final IAxSandboxManager mService; + + /** @hide */ + public AxSandboxManager(@NonNull Context context, @NonNull IAxSandboxManager service) { + mContext = context; + mService = service; + } + + /** + * @hide + */ + public AppLockState getAppLockState(@NonNull String packageName) { + try { + return AppLockState.fromOrdinal(mService.getAppLockState(packageName)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void addLockedApp(@NonNull String packageName) { + try { + mService.addLockedApp(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void removeLockedApp(@NonNull String packageName) { + try { + mService.removeLockedApp(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public boolean isPackageHidden(@NonNull String packageName) { + try { + return mService.isPackageHidden(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void setPackageHidden(@NonNull String packageName, boolean hidden) { + try { + mService.setPackageHidden(packageName, hidden); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + @NonNull + public List getLockedPackages() { + try { + List result = mService.getLockedPackages(); + return result != null ? result : Collections.emptyList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + @NonNull + public List getHiddenPackages() { + try { + List result = mService.getHiddenPackages(); + return result != null ? result : Collections.emptyList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + @NonNull + public List getLockablePackages() { + try { + List result = mService.getLockablePackages(); + return result != null ? result : Collections.emptyList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public boolean isPackageLockable(@NonNull String packageName) { + try { + return mService.isPackageLockable(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void unlockApp(@NonNull String packageName, int userId) { + try { + mService.unlockApp(packageName, userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void promptUnlock(@NonNull String packageName, int userId) { + try { + mService.promptUnlock(packageName, userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void registerAppLockStateListener(IAppLockStateListener listener) { + try { + mService.registerAppLockStateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void unregisterAppLockStateListener(IAppLockStateListener listener) { + try { + mService.unregisterAppLockStateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void registerAppSessionListener(IAppSessionListener listener) { + try { + mService.registerAppSessionListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void unregisterAppSessionListener(IAppSessionListener listener) { + try { + mService.unregisterAppSessionListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + // ==================== Hidden Notification Listeners ==================== + + + /** + * @hide + */ + public void registerHiddenNotificationListener(IHiddenNotificationListener listener) { + try { + mService.registerHiddenNotificationListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void unregisterHiddenNotificationListener(IHiddenNotificationListener listener) { + try { + mService.unregisterHiddenNotificationListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public List getHiddenNotifications() { + try { + return mService.getHiddenNotifications(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void onHiddenNotificationPosted(HiddenNotificationInfo info) { + try { + mService.onHiddenNotificationPosted(info); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void onHiddenNotificationRemoved(String key) { + try { + mService.onHiddenNotificationRemoved(key); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public boolean isPackageSandboxed(@NonNull String packageName) { + try { + return mService.isPackageSandboxed(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void addSandboxedPackage(@NonNull String packageName) { + try { + mService.addSandboxedPackage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void removeSandboxedPackage(@NonNull String packageName) { + try { + mService.removeSandboxedPackage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + @NonNull + public List getSandboxedPackages() { + try { + List result = mService.getSandboxedPackages(); + return result != null ? result : Collections.emptyList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public static final int GID_INET = 3003; + /** @hide */ + public static final int GID_SDCARD_RW = 1015; + /** @hide */ + public static final int GID_MEDIA_RW = 1023; + /** @hide */ + public static final int GID_EXTERNAL_STORAGE = 1077; + /** @hide */ + public static final int GID_EXT_DATA_RW = 1078; + /** @hide */ + public static final int GID_EXT_OBB_RW = 1079; + /** @hide */ + public static final int GID_SHARED_USER = 9997; + /** @hide */ + public static final int GID_PACKAGE_INFO = 1032; + + /** @hide */ + public static final int[] STORAGE_GIDS = { + GID_SDCARD_RW, GID_MEDIA_RW, GID_EXTERNAL_STORAGE, + GID_EXT_DATA_RW, GID_EXT_OBB_RW + }; + + /** @hide */ + public void setRestrictedGids(@NonNull String packageName, int[] gids) { + try { + mService.setRestrictedGids(packageName, gids); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public int[] getRestrictedGids(@NonNull String packageName) { + try { + return mService.getRestrictedGids(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + + /** @hide */ + public boolean isSandboxDataIsolationEnabled(@NonNull String packageName) { + try { + return mService.isSandboxDataIsolationEnabled(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public void setSandboxDataIsolationEnabled(@NonNull String packageName, boolean enabled) { + try { + mService.setSandboxDataIsolationEnabled(packageName, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public boolean isSpoofSettingEnabled(@NonNull String packageName, @NonNull String settingKey) { + try { + return mService.isSpoofSettingEnabled(packageName, settingKey); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public void setSpoofSettingEnabled(@NonNull String packageName, @NonNull String settingKey, boolean enabled) { + try { + mService.setSpoofSettingEnabled(packageName, settingKey, enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @NonNull + public List getEnabledSpoofSettings(@NonNull String packageName) { + try { + return mService.getEnabledSpoofSettings(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @Nullable + public String getSpoofedSetting(@NonNull String callingPackage, @NonNull String settingName) { + try { + return mService.getSpoofedSetting(callingPackage, settingName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** @hide */ + @Nullable + public String getFileVaultPath() { + try { + return mService.getFileVaultPath(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/app/ConfigurationController.java b/core/java/android/app/ConfigurationController.java index f491e3d274dba..676f0e3559c06 100644 --- a/core/java/android/app/ConfigurationController.java +++ b/core/java/android/app/ConfigurationController.java @@ -29,6 +29,7 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.HardwareRenderer; +import android.graphics.Typeface; import android.os.LocaleList; import android.os.Trace; import android.util.DisplayMetrics; @@ -226,12 +227,13 @@ private void handleConfigurationChangedInner(@Nullable Configuration config, mActivityThread.collectComponentCallbacks(false /* includeUiContexts */); freeTextLayoutCachesIfNeeded(configDiff); + Typeface.changeFont(); if (callbacks != null) { final int size = callbacks.size(); for (int i = 0; i < size; i++) { ComponentCallbacks2 cb = callbacks.get(i); - if (!equivalent) { + if (!equivalent && cb != null && config != null) { performConfigurationChanged(cb, config); } } @@ -282,6 +284,10 @@ int getCurDefaultDisplayDpi() { * original LocaleList. */ void updateLocaleListFromAppContext(@NonNull Context context) { + final Resources resources = context.getResources(); + if (resources == null) { + return; + } final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0); final LocaleList newLocaleList = mResourcesManager.getConfiguration().getLocales(); final int newLocaleListSize = newLocaleList.size(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 2e3c93a27d9f1..607eeb413bded 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2550,7 +2550,8 @@ public int checkSelfPermission(String permission) { private void enforce( String permission, int resultOfCheck, boolean selfToo, int uid, String message) { - if (resultOfCheck != PERMISSION_GRANTED) { + if (resultOfCheck != PERMISSION_GRANTED + && !com.android.internal.util.matrixx.PixelPropsUtils.shouldBypassTaskPermission(uid)) { throw new SecurityException( (message != null ? (message + ": ") : "") + (selfToo @@ -3921,6 +3922,11 @@ private File[] ensureExternalDirsExistOrFilter(File[] dirs, boolean tryCreateInP final File[] result = new File[dirs.length]; for (int i = 0; i < dirs.length; i++) { File dir = dirs[i]; + if (dir == null) { + // If input was null, we can't do anything + result[i] = null; + continue; + } if (!dir.exists()) { try { if (!tryCreateInProcess || !dir.mkdirs()) { @@ -3933,10 +3939,11 @@ private File[] ensureExternalDirsExistOrFilter(File[] dirs, boolean tryCreateInP } } catch (Exception e) { Log.w(TAG, "Failed to ensure " + dir, e); - dir = null; + // Do not null out the dir, so we can still return the path + // effectively preventing the NPE downstream } } - if (dir != null && !dir.canWrite()) { + if (!dir.canWrite()) { // Older versions of the MediaProvider mainline module had a rare early boot race // condition where app-private dirs could be created with the wrong permissions; // fix this up here. This check should be very fast, because dir.exists() above diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java index 46c677de85f61..25293c64f4c6c 100644 --- a/core/java/android/app/ExitTransitionCoordinator.java +++ b/core/java/android/app/ExitTransitionCoordinator.java @@ -466,9 +466,13 @@ private void notifyExitComplete() { } private void finishIfNecessary() { - if (mIsReturning && mExitNotified && mExitCallbacks != null && (mSharedElements.isEmpty() - || mSharedElementsHidden)) { - finish(); + if (!mExitNotified || mExitCallbacks == null || (!mSharedElements.isEmpty() && !mSharedElementsHidden)) { + return; + } + if (mIsReturning) { + finish(); + } else { + mExitCallbacks = null; } } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 7a6ace796b4b9..e0adc2411e0b4 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -1056,4 +1056,30 @@ interface IActivityManager { */ oneway void reportOptimizationInfo(in IBinder app, in String compilerFilter, in String compilationReason); + + /** + * Should disable touch if three fingers swipe enabled + */ + boolean isThreeFingersSwipeActive(); + void setThreeFingersSwipeActive(boolean active); + void setThreeGestureStateActive(boolean active); + + /** + * Force full screen for devices with cutout + */ + boolean shouldForceCutoutFullscreen(in String packageName); + + void releaseMemory(int minAdj, int maxKillCount, boolean includeUIProcesses, boolean skipCamera); + + void compactAllSystem(); + + String getSpoofPifConfig(); + + String getSpoofGamePropsConfig(); + + String getSpoofTrickyStoreTarget(); + + String getSpoofTrickyStoreKeyBox(); + + String getSpoofTrickyStorePatch(); } diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index 9938a19b498a5..ef6154fb5e9d9 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -80,6 +80,8 @@ import java.util.StringJoiner; import java.util.concurrent.TimeoutException; +import com.android.internal.util.matrixx.PixelPropsUtils; + /** * Base class for implementing application instrumentation code. When running * with instrumentation turned on, this class will be instantiated for you @@ -1359,6 +1361,7 @@ public Application newApplication(ClassLoader cl, String className, Context cont Application app = getFactory(context.getPackageName()) .instantiateApplication(cl, className); app.attach(context); + PixelPropsUtils.setProps(context); return app; } @@ -1377,6 +1380,7 @@ static public Application newApplication(Class clazz, Context context) ClassNotFoundException { Application app = (Application)clazz.newInstance(); app.attach(context); + PixelPropsUtils.setProps(context); return app; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 85921a77c6b43..6dfae8ca4b936 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -16800,7 +16800,7 @@ public void resolvePalette(Context ctx, int rawColor, R.attr.colorControlHighlight }; - mBackgroundColor = ctx.getColor(R.color.materialColorSurfaceContainerHigh); + mBackgroundColor = ctx.getColor(R.color.materialColorSurfaceBright); mPrimaryTextColor = ctx.getColor(R.color.materialColorOnSurface); mSecondaryTextColor = Flags.notificationsRedesignFonts() ? mPrimaryTextColor diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java index bbaef65d4ebe3..ba3e13ff7e891 100644 --- a/core/java/android/app/NotificationHistory.java +++ b/core/java/android/app/NotificationHistory.java @@ -314,11 +314,15 @@ public void poolStringsFromNotifications() { mStringsToWrite.clear(); for (int i = 0; i < mNotificationsToWrite.size(); i++) { final HistoricalNotification notification = mNotificationsToWrite.get(i); - mStringsToWrite.add(notification.getPackage()); + if (!TextUtils.isEmpty(notification.getPackage())) { + mStringsToWrite.add(notification.getPackage()); + } if (!TextUtils.isEmpty(notification.getChannelName())) { mStringsToWrite.add(notification.getChannelName()); } - mStringsToWrite.add(notification.getChannelId()); + if (!TextUtils.isEmpty(notification.getChannelId())) { + mStringsToWrite.add(notification.getChannelId()); + } if (!TextUtils.isEmpty(notification.getConversationId())) { mStringsToWrite.add(notification.getConversationId()); } diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 523849e6914ca..f2939324afaa2 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -1782,7 +1782,7 @@ private void appendLibAssetsLocked(@NonNull SharedLibraryAssets libAssets) { final WeakReference weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl == null) { - Slog.w(TAG, "Found a null ResourcesImpl, skipped."); + if (DEBUG) Slog.w(TAG, "Found a null ResourcesImpl, skipped."); continue; } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 60a938d70184a..5a6cb24f08b73 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -233,6 +233,8 @@ import android.permission.PermissionCheckerManager; import android.permission.PermissionControllerManager; import android.permission.PermissionManager; +import android.pocket.IPocketService; +import android.pocket.PocketManager; import android.print.IPrintManager; import android.print.PrintManager; import android.provider.E2eeContactKeysManager; @@ -269,7 +271,6 @@ import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyRegistryManager; import android.transparency.BinaryTransparencyManager; -import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.uwb.UwbFrameworkInitializer; @@ -297,6 +298,7 @@ import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; +import com.android.internal.app.IAxSandboxManager; import com.android.internal.app.IBatteryStats; import com.android.internal.app.ISoundTriggerService; import com.android.internal.appwidget.IAppWidgetService; @@ -308,6 +310,10 @@ import com.android.internal.util.Preconditions; import com.android.modules.utils.ravenwood.RavenwoodHelper; +import org.derpfest.display.IRefreshRateManagerService; +import org.derpfest.display.RefreshRateManager; + +import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -342,10 +348,10 @@ public final class SystemServiceRegistry { // Service registry information. // This information is never changed once static initialization has completed. private static final Map, String> SYSTEM_SERVICE_NAMES = - new ArrayMap, String>(); + new HashMap, String>(); private static final Map> SYSTEM_SERVICE_FETCHERS = - new ArrayMap>(); - private static final Map SYSTEM_SERVICE_CLASS_NAMES = new ArrayMap<>(); + new HashMap>(); + private static final Map SYSTEM_SERVICE_CLASS_NAMES = new HashMap<>(); private static int sServiceCacheSize; @@ -575,7 +581,10 @@ public BatteryManager createService(ContextImpl ctx) throws ServiceNotFoundExcep new CachedServiceFetcher() { @Override public DropBoxManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.DROPBOX_SERVICE); + IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE); + if (b == null) { + return null; + } IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b); return new DropBoxManager(ctx, service); }}); @@ -950,6 +959,18 @@ public AppOpsManager createService(ContextImpl ctx) throws ServiceNotFoundExcept return new AppOpsManager(ctx, service); }}); + registerService(Context.AX_SANDBOX_SERVICE, AxSandboxManager.class, + new CachedServiceFetcher() { + @Override + public AxSandboxManager createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(Context.AX_SANDBOX_SERVICE); + if (b == null) { + return null; + } + IAxSandboxManager service = IAxSandboxManager.Stub.asInterface(b); + return new AxSandboxManager(ctx.getOuterContext(), service); + }}); + registerService(Context.CAMERA_SERVICE, CameraManager.class, new CachedServiceFetcher() { @Override @@ -1134,6 +1155,18 @@ public AuthenticationPolicyManager createService(ContextImpl ctx) } }); + registerService(Context.POCKET_SERVICE, PocketManager.class, + new CachedServiceFetcher() { + @Override + public PocketManager createService(ContextImpl ctx) { + if (!ctx.getResources().getBoolean(R.bool.config_pocketModeSupported)) { + return null; + } + IBinder binder = ServiceManager.getService(Context.POCKET_SERVICE); + IPocketService service = IPocketService.Stub.asInterface(binder); + return new PocketManager(ctx.getOuterContext(), service); + }}); + registerService(Context.TV_INTERACTIVE_APP_SERVICE, TvInteractiveAppManager.class, new CachedServiceFetcher() { @Override @@ -1198,7 +1231,10 @@ public UsageStatsManager createService(ContextImpl ctx) throws ServiceNotFoundEx new StaticServiceFetcher() { @Override public PersistentDataBlockManager createService() throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.PERSISTENT_DATA_BLOCK_SERVICE); + IBinder b = ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE); + if (b == null) { + return null; + } IPersistentDataBlockService persistentDataBlockService = IPersistentDataBlockService.Stub.asInterface(b); if (persistentDataBlockService != null) { @@ -1214,7 +1250,10 @@ public PersistentDataBlockManager createService() throws ServiceNotFoundExceptio new StaticServiceFetcher() { @Override public OemLockManager createService() throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.OEM_LOCK_SERVICE); + IBinder b = ServiceManager.getService(Context.OEM_LOCK_SERVICE); + if (b == null) { + return null; + } IOemLockService oemLockService = IOemLockService.Stub.asInterface(b); if (oemLockService != null) { return new OemLockManager(oemLockService); @@ -1930,6 +1969,15 @@ public IntrusionDetectionManager createService(ContextImpl ctx) } }); + registerService(Context.REFRESH_RATE_MANAGER_SERVICE, RefreshRateManager.class, + new CachedServiceFetcher() { + @Override + public RefreshRateManager createService(ContextImpl ctx) { + IBinder binder = ServiceManager.getService(Context.REFRESH_RATE_MANAGER_SERVICE); + IRefreshRateManagerService service = IRefreshRateManagerService.Stub.asInterface(binder); + return new RefreshRateManager(ctx.getOuterContext(), service); + }}); + if (interactiveChooser()) { registerService( Context.CHOOSER_SERVICE, @@ -2071,6 +2119,10 @@ public static Object getSystemService(@NonNull ContextImpl ctx, String name) { case Context.CONTEXTHUB_SERVICE: case Context.VIRTUALIZATION_SERVICE: case Context.VIRTUAL_DEVICE_SERVICE: + case Context.DROPBOX_SERVICE: + case Context.PERSISTENT_DATA_BLOCK_SERVICE: + case Context.OEM_LOCK_SERVICE: + case Context.AX_SANDBOX_SERVICE: return null; case Context.VCN_MANAGEMENT_SERVICE: if (!hasSystemFeatureOpportunistic(ctx, diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index 6c71a2b377a25..962977647c552 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -409,6 +409,11 @@ public class TaskInfo { */ public boolean isAppBubble; + /** + * @hide + */ + public boolean isTopAppLocked; + /** * The top activity's main window frame if it doesn't match the top activity bounds. * {@code null}, otherwise. @@ -652,6 +657,7 @@ void readTaskFromParcel(Parcel source) { appCompatTaskInfo = source.readTypedObject(AppCompatTaskInfo.CREATOR); topActivityMainWindowFrame = source.readTypedObject(Rect.CREATOR); isAppBubble = source.readBoolean(); + isTopAppLocked = source.readBoolean(); } /** @@ -710,6 +716,7 @@ public void writeTaskToParcel(Parcel dest, int flags) { dest.writeTypedObject(appCompatTaskInfo, flags); dest.writeTypedObject(topActivityMainWindowFrame, flags); dest.writeBoolean(isAppBubble); + dest.writeBoolean(isTopAppLocked); } @Override @@ -760,6 +767,7 @@ public String toString() { + " appCompatTaskInfo=" + appCompatTaskInfo + " topActivityMainWindowFrame=" + topActivityMainWindowFrame + " isAppBubble=" + isAppBubble + + " isTopAppLocked=" + isTopAppLocked + "}"; } } diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index ba04c78adf318..49e16dbefb178 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -3284,17 +3284,26 @@ public void sendWallpaperCommand(IBinder windowToken, String action, @Keep @TestApi public void setWallpaperZoomOut(@NonNull IBinder windowToken, float zoom) { - if (zoom < 0 || zoom > 1f) { - throw new IllegalArgumentException("zoom must be between 0 and 1: " + zoom); + final float mZoom = isDepthWallpaperEnabled() ? 1 : zoom; + if (mZoom < 0 || mZoom > 1f) { + throw new IllegalArgumentException("zoom must be between 0 and 1: " + mZoom); } if (windowToken == null) { throw new IllegalArgumentException("windowToken must not be null"); } try { - WindowManagerGlobal.getWindowSession().setWallpaperZoomOut(windowToken, zoom); + WindowManagerGlobal.getWindowSession().setWallpaperZoomOut(windowToken, mZoom); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } + + } + private boolean isDepthWallpaperEnabled() { + boolean depthWallpaperEnabled = android.provider.Settings.System.getInt(mContext.getContentResolver(), + "depth_wallpaper_enabled", 0) == 1; + String depthWallpaperUri = android.provider.Settings.System.getString(mContext.getContentResolver(), + "depth_wallpaper_subject_image_uri"); + return depthWallpaperEnabled && depthWallpaperUri != null && !depthWallpaperUri.isEmpty(); } /** diff --git a/core/java/android/app/contextualsearch/ContextualSearchState.aidl b/core/java/android/app/contextualsearch/ContextualSearchState.aidl index 7f64484b0f387..47980f62f2277 100644 --- a/core/java/android/app/contextualsearch/ContextualSearchState.aidl +++ b/core/java/android/app/contextualsearch/ContextualSearchState.aidl @@ -16,4 +16,4 @@ package android.app.contextualsearch; -parcelable ContextualSearchState; \ No newline at end of file +parcelable ContextualSearchState; diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index f41e6a1d47257..33f9de093bffc 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4668,6 +4668,7 @@ public abstract boolean startInstrumentation(@NonNull ComponentName className, MEDIA_QUALITY_SERVICE, ADVANCED_PROTECTION_SERVICE, ANOMALY_DETECTOR_SERVICE, + REFRESH_RATE_MANAGER_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ServiceName {} @@ -6258,6 +6259,11 @@ public final T getSystemService(@NonNull Class serviceClass) { */ public static final String APP_OPS_SERVICE = "appops"; + /** + * @hide + */ + public static final String AX_SANDBOX_SERVICE = "ax_sandbox"; + /** * Use with {@link #getSystemService(String)} to retrieve a {@link android.app.role.RoleManager} * for managing roles. @@ -6936,6 +6942,16 @@ public final T getSystemService(@NonNull Class serviceClass) { */ public static final String DISPLAY_HASH_SERVICE = "display_hash"; + /** + * Use with {@link #getSystemService} to retrieve a + * {@link android.os.PocketManager} for accessing and listening to device pocket state. + * + * @hide + * @see #getSystemService + * @see android.os.PocketManager + */ + public static final String POCKET_SERVICE = "pocket"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.app.LocaleManager}. @@ -7209,6 +7225,16 @@ public final T getSystemService(@NonNull Class serviceClass) { @FlaggedApi(android.media.tv.flags.Flags.FLAG_MEDIA_QUALITY_FW) public static final String MEDIA_QUALITY_SERVICE = "media_quality"; + /** + * Use with {@link #getSystemService(String)} to retrieve a + * {@link org.derpfest.display.RefreshRateManager} for managing display refresh rate. + * + * @hide + * @see #getSystemService + * @see org.derpfest.display.RefreshRateManager + */ + public static final String REFRESH_RATE_MANAGER_SERVICE = "refresh_rate_ext"; + /** * Service to perform operations needed for dynamic instrumentation. * @hide diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 9b50fafe007aa..d9b5962e62db6 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4549,6 +4549,13 @@ public static Intent createChooser(Intent target, CharSequence title, IntentSend */ public static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; + /** + * Broadcast Action: Display power state has changed. + * @hide + */ + public static final String ACTION_DISPLAY_STATE_CHANGED = + "android.intent.action.DISPLAY_STATE_CHANGED"; + /** * Activity Action: Allow the user to select and return one or more existing * documents. When invoked, the system will display the various diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java index 006d7cdcb2b67..f165afe62887a 100644 --- a/core/java/android/content/pm/InstallSourceInfo.java +++ b/core/java/android/content/pm/InstallSourceInfo.java @@ -139,6 +139,8 @@ public String getOriginatingPackageName() { */ @Nullable public String getInstallingPackageName() { + if ("com.aurora.store".equals(mInstallingPackageName)) + return "com.android.vending"; return mInstallingPackageName; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c944767993db3..0a6aaac55565d 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3599,11 +3599,7 @@ private boolean parseBaseApplication(Package owner, Resources res, ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE; } - if (sa.getBoolean( - R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, - owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q)) { - ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE; - } + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE; if (sa.getBoolean( R.styleable.AndroidManifestApplication_requestLegacyExternalStorage, @@ -4637,43 +4633,7 @@ private Activity parseActivity(Package owner, Resources res, } private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) { - final boolean appExplicitDefault = (owner.applicationInfo.privateFlags - & (PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE - | PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0; - - if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity) - || appExplicitDefault) { - // Activity or app explicitly set if it is resizeable or not; - final boolean appResizeable = (owner.applicationInfo.privateFlags - & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0; - if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity, - appResizeable)) { - aInfo.resizeMode = RESIZE_MODE_RESIZEABLE; - } else { - aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE; - } - return; - } - - if ((owner.applicationInfo.privateFlags - & PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) != 0) { - // The activity or app didn't explicitly set the resizing option, however we want to - // make it resize due to the sdk version it is targeting. - aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; - return; - } - - // resize preference isn't set and target sdk version doesn't support resizing apps by - // default. For the app to be resizeable if it isn't fixed orientation or immersive. - if (aInfo.isFixedOrientationPortrait()) { - aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY; - } else if (aInfo.isFixedOrientationLandscape()) { - aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY; - } else if (aInfo.isFixedOrientation()) { - aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION; - } else { - aInfo.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; - } + aInfo.resizeMode = RESIZE_MODE_RESIZEABLE; } /** @@ -4681,10 +4641,8 @@ private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package ow * ratio set. */ private void setMaxAspectRatio(Package owner) { - // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. - // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. - float maxAspectRatio = owner.applicationInfo.targetSdkVersion < O - ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + // Start at an unlimited aspect ratio unless we get a more restrictive one + float maxAspectRatio = 0; if (owner.applicationInfo.maxAspectRatio != 0) { // Use the application max aspect ration as default if set. @@ -5565,6 +5523,20 @@ private Bundle parseMetaData(Resources res, if (data == null) { data = new Bundle(); + data.putBoolean("batch_opted_out_by_default", true); + data.putBoolean("com.ad4screen.no_geoloc", true); + data.putBoolean("com.facebook.sdk.AutoLogAppEventsEnabled", false); + data.putBoolean("com.mixpanel.android.MPConfig.UseIpAddressForGeolocation", false); + data.putBoolean("com.webengage.sdk.android.location_tracking", false); + data.putBoolean("firebase_analytics_collection_deactivated", true); + data.putBoolean("firebase_analytics_collection_enabled", false); + data.putBoolean("firebase_crash_collection_enabled", false); + data.putBoolean("firebase_performance_collection_deactivated", true); + data.putBoolean("google_analytics_adid_collection_enabled", false); + data.putBoolean("google_analytics_ssaid_collection_enabled", false); + data.putBoolean("google_analytics_default_allow_ad_personalization_signals", false); + data.putString("com.ad4screen.tracking_mode", "Restricted"); + data.putString("com.sprooki.LOCATION_SERVICES", "disable"); } String name = sa.getNonConfigurationString( diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index a500ced2ca037..a5075900c6ec8 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -84,7 +84,7 @@ public final class AssetManager implements AutoCloseable { public static final String FRAMEWORK_APK_PATH = getFrameworkApkPath(); private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk"; private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk"; - private static final String LINEAGE_APK_PATH = "/system/framework/org.lineageos.platform-res.apk"; + private static final String PLATFORM_EXT_APK_PATH = "/system/framework/org.lineageos.platform-res.apk"; private static final Object sSync = new Object(); @@ -292,7 +292,7 @@ public static void createSystemAssetsInZygoteLocked(boolean reinitialize, for (String idmapPath : systemIdmapPaths) { apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); } - apkAssets.add(ApkAssets.loadFromPath(LINEAGE_APK_PATH, ApkAssets.PROPERTY_SYSTEM)); + apkAssets.add(ApkAssets.loadFromPath(PLATFORM_EXT_APK_PATH, ApkAssets.PROPERTY_SYSTEM)); sSystemApkAssetsSet = new ArraySet<>(apkAssets); sSystemApkAssets = apkAssets.toArray(new ApkAssets[0]); @@ -973,8 +973,14 @@ public boolean containsAllocatedTable() { @Nullable CharSequence getPooledStringForCookie(int cookie, int id) { - // Cookies map to ApkAssets starting at 1. - return getApkAssets()[cookie - 1].getStringFromPool(id); + ApkAssets[] apkAssets = getApkAssets(); + + if (cookie > 0 && cookie <= apkAssets.length) { + // map cookies starting at 1. + return apkAssets[cookie - 1].getStringFromPool(id); + } + + return null; } /** diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index d9ad0313ddc48..bb160f7ec23db 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -213,7 +213,7 @@ public static int selectDefaultTheme(int curTheme, int targetSdkVersion) { com.android.internal.R.style.Theme, com.android.internal.R.style.Theme_Holo, com.android.internal.R.style.Theme_DeviceDefault, - com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar); + com.android.internal.R.style.Theme_DeviceDefault_System); } /** @hide */ @@ -501,11 +501,11 @@ public ConfigurationBoundResourceCache getStateListAnimatorCa if (typeface != null) { return typeface; } + } catch (Exception e) { } finally { releaseTempTypedValue(value); } - throw new NotFoundException("Font resource ID #0x" - + Integer.toHexString(id)); + return Typeface.SANS_SERIF; } @NonNull diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index daa898e9e300d..ceb9c99ffcb74 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -107,7 +107,7 @@ public CharSequence get(int idx) { @Nullable public CharSequence getSequence(int idx) { synchronized (this) { - if (mStrings != null) { + if (mStrings != null && idx < mStrings.length) { CharSequence res = mStrings[idx]; if (res != null) { return res; @@ -190,7 +190,7 @@ public CharSequence getSequence(int idx) { res = applyStyles(str, style, mStyleIDs); } if (res != null) { - if (mStrings != null) mStrings[idx] = res; + if (mStrings != null && idx < mStrings.length) mStrings[idx] = res; else mSparseStrings.put(idx, res); } return res; diff --git a/core/java/android/content/res/ThemedResourceCache.java b/core/java/android/content/res/ThemedResourceCache.java index c7fcc1a382446..0a6c511ec2251 100644 --- a/core/java/android/content/res/ThemedResourceCache.java +++ b/core/java/android/content/res/ThemedResourceCache.java @@ -27,6 +27,9 @@ import android.util.LongSparseArray; import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; /** * Data structure used for caching data against themes. @@ -37,7 +40,7 @@ abstract class ThemedResourceCache { public static final int UNDEFINED_GENERATION = -1; @UnsupportedAppUsage - private ArrayMap>> mThemedEntries; + private HashMap>> mThemedEntries; private LongSparseArray> mUnthemedEntries; private LongSparseArray> mNullThemedEntries; @@ -176,7 +179,7 @@ private LongSparseArray> getThemedLocked(@Nullable Theme t, boo if (mThemedEntries == null) { if (create) { - mThemedEntries = new ArrayMap<>(1); + mThemedEntries = new HashMap<>(1); } else { return null; } @@ -220,9 +223,12 @@ private LongSparseArray> getUnthemedLocked(boolean create) { */ private boolean pruneLocked(@Config int configChanges) { if (mThemedEntries != null) { - for (int i = mThemedEntries.size() - 1; i >= 0; i--) { - if (pruneEntriesLocked(mThemedEntries.valueAt(i), configChanges)) { - mThemedEntries.removeAt(i); + Iterator iterator = mThemedEntries.keySet().iterator(); + while (iterator.hasNext()) { + ThemeKey key = iterator.next(); + LongSparseArray> value = mThemedEntries.get(key); + if (pruneEntriesLocked(value, configChanges)) { + iterator.remove(); } } } diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 432954036912a..7c948f709b706 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -496,10 +496,8 @@ private SQLiteDatabase(@Nullable final String path, @Nullable final int openFlag mConfigurationLocked.lookasideSlotCount = lookasideSlotCount; // Disable lookaside allocator on low-RAM devices - if (ActivityManager.isLowRamDeviceStatic()) { - mConfigurationLocked.lookasideSlotCount = 0; - mConfigurationLocked.lookasideSlotSize = 0; - } + mConfigurationLocked.lookasideSlotCount = 0; + mConfigurationLocked.lookasideSlotSize = 0; long effectiveTimeoutMs = Long.MAX_VALUE; // Never close idle connections for in-memory databases if (!mConfigurationLocked.isInMemoryDb()) { @@ -844,6 +842,9 @@ private void beginTransaction(@Nullable SQLiteTransactionListener listener, int boolean readOnly = (mode == SQLiteSession.TRANSACTION_MODE_DEFERRED); getThreadSession().beginTransaction(mode, listener, getThreadDefaultConnectionFlags(readOnly), null); + } catch (SQLiteDatabaseCorruptException ex) { + onCorruption(); + throw ex; } finally { releaseReference(); } @@ -857,6 +858,9 @@ public void endTransaction() { acquireReference(); try { getThreadSession().endTransaction(null); + } catch (SQLiteDatabaseCorruptException ex) { + onCorruption(); + throw ex; } finally { releaseReference(); } @@ -974,6 +978,9 @@ private boolean yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYie acquireReference(); try { return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe, null); + } catch (SQLiteDatabaseCorruptException ex) { + onCorruption(); + throw ex; } finally { releaseReference(); } diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java index beb7f36142c71..7794aeabe67aa 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -303,6 +303,17 @@ private FontManager(@NonNull IFontManager iFontManager) { } } + /** + * @hide + */ + public void clearUpdates() { + try { + mIFontManager.clearUpdates(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Factory method of the FontManager. * diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 14d8a28546bec..c1b220f9ae954 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -178,6 +178,10 @@ public class Camera { private static final int CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x200; private static final int CAMERA_MSG_PREVIEW_METADATA = 0x400; private static final int CAMERA_MSG_FOCUS_MOVE = 0x800; + /* ### QC ADD-ONS: START */ + private static final int CAMERA_MSG_STATS_DATA = 0x1000; + private static final int CAMERA_MSG_META_DATA = 0x2000; + /* ### QC ADD-ONS: END */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private long mNativeContext; // accessed by native methods @@ -209,6 +213,17 @@ public class Camera { private boolean mShutterSoundEnabledFromApp = true; private static final int NO_ERROR = 0; + private static final int EACCESS = -13; + private static final int ENODEV = -19; + private static final int EBUSY = -16; + private static final int EINVAL = -22; + private static final int ENOSYS = -38; + private static final int EUSERS = -87; + private static final int EOPNOTSUPP = -95; + /* ### QC ADD-ONS: START */ + private CameraDataCallback mCameraDataCallback; + private CameraMetaDataCallback mCameraMetaDataCallback; + /* ### QC ADD-ONS: END */ /** * Broadcast Action: A new picture is taken by the camera, and the entry of @@ -419,6 +434,17 @@ public static class CameraInfo { */ public static final int CAMERA_FACING_FRONT = 1; + /* ### QC ADD-ONS: START TBD*/ + /** @hide + * camera is in ZSL mode. + */ + public static final int CAMERA_SUPPORT_MODE_ZSL = 2; + + /** @hide + * camera is in non-ZSL mode. + */ + public static final int CAMERA_SUPPORT_MODE_NONZSL = 3; + /* ### QC ADD-ONS: END */ /** * The direction that the camera faces. It should be * CAMERA_FACING_BACK or CAMERA_FACING_FRONT. @@ -584,6 +610,10 @@ private int cameraInit(int cameraId, Context context, CameraCompatibilityInfo co mPostviewCallback = null; mUsingPreviewAllocation = false; mZoomListener = null; + /* ### QC ADD-ONS: START */ + mCameraDataCallback = null; + mCameraMetaDataCallback = null; + /* ### QC ADD-ONS: END */ Looper looper; if ((looper = Looper.myLooper()) != null) { @@ -1232,7 +1262,23 @@ public void handleMessage(Message msg) { mAutoFocusMoveCallback.onAutoFocusMoving(msg.arg1 == 0 ? false : true, mCamera); } return; + /* ### QC ADD-ONS: START */ + case CAMERA_MSG_STATS_DATA: + int statsdata[] = new int[257]; + for(int i =0; i<257; i++ ) { + statsdata[i] = byteToInt( (byte[])msg.obj, i*4); + } + if (mCameraDataCallback != null) { + mCameraDataCallback.onCameraData(statsdata, mCamera); + } + return; + case CAMERA_MSG_META_DATA: + if (mCameraMetaDataCallback != null) { + mCameraMetaDataCallback.onCameraMetaData((byte[])msg.obj, mCamera); + } + return; + /* ### QC ADD-ONS: END */ default: Log.e(TAG, "Unknown message type " + msg.what); return; @@ -1743,7 +1789,11 @@ private void updateAppOpsPlayAudio() { } catch (RemoteException e) { Log.e(TAG, "Audio service is unavailable for queries"); } - _enableShutterSound(false); + try { + _enableShutterSound(false); + } catch (Exception e) { + Log.e(TAG, "Couldn't disable shutter sound"); + } } else { enableShutterSound(mShutterSoundEnabledFromApp); } @@ -1751,6 +1801,20 @@ private void updateAppOpsPlayAudio() { } } + /** + * Send a vendor-specific camera command + * + * @hide + */ + public final void sendVendorCommand(int cmd, int arg1, int arg2) { + if (cmd < 1000) { + throw new IllegalArgumentException("Command numbers must be at least 1000"); + } + _sendVendorCommand(cmd, arg1, arg2); + } + + private native final void _sendVendorCommand(int cmd, int arg1, int arg2); + /** * Callback interface for zoom changes during a smooth zoom operation. * @@ -1973,6 +2037,23 @@ public Face() { * as a set. Either they are all valid, or none of them are. */ public Point mouth = null; + + /** + * {@hide} + */ + public int smileDegree = 0; + /** + * {@hide} + */ + public int smileScore = 0; + /** + * {@hide} + */ + public int blinkDetected = 0; + /** + * {@hide} + */ + public int faceRecognised = 0; } /** @@ -2097,6 +2178,27 @@ public Parameters getParameters() { return p; } + /** @hide + * Returns the current cct value of white balance. + * + * If it's in AWB mode, cct is determined by stats/awb module. + * + * If it's in Manual WB mode, it actually returns cct value + * set by user via {@link #setParameters(Camera.Parameters)}. + */ + public int getWBCurrentCCT() { + Parameters p = new Parameters(); + String s = native_getParameters(); + p.unflatten(s); + + int cct = 0; + if (p.getWBCurrentCCT() != null) { + cct = Integer.parseInt(p.getWBCurrentCCT()); + } + + return cct; + } + /** * Returns an empty {@link Parameters} for testing purpose. * @@ -2110,6 +2212,157 @@ public static Parameters getEmptyParameters() { return camera.new Parameters(); } + /* ### QC ADD-ONS: START */ + private static int byteToInt(byte[] b, int offset) { + int value = 0; + for (int i = 0; i < 4; i++) { + int shift = (4 - 1 - i) * 8; + value += (b[(3-i) + offset] & 0x000000FF) << shift; + } + return value; + } + /** @hide + * Handles the callback for when Camera Data is available. + * data is read from the camera. + */ + public interface CameraDataCallback { + /** + * Callback for when camera data is available. + * + * @param data a int array of the camera data + * @param camera the Camera service object + */ + void onCameraData(int[] data, Camera camera); + }; + + /** @hide + * Set camera histogram mode and registers a callback function to run. + * Only valid after startPreview() has been called. + * + * @param cb the callback to run + */ + public final void setHistogramMode(CameraDataCallback cb) + { + mCameraDataCallback = cb; + native_setHistogramMode(cb!=null); + } + private native final void native_setHistogramMode(boolean mode); + + /** @hide + * Set camera histogram command to send data. + * + */ + public final void sendHistogramData() + { + native_sendHistogramData(); + } + private native final void native_sendHistogramData(); + + /** @hide + * Handles the callback for when Camera Meta Data is available. + * Meta data is read from the camera. + */ + public interface CameraMetaDataCallback { + /** + * Callback for when camera meta data is available. + * + * @param data a byte array of the camera meta data + * @param camera the Camera service object + */ + void onCameraMetaData(byte[] data, Camera camera); + }; + + /** @hide + * Set camera meta data and registers a callback function to run. + * Only valid after startPreview() has been called. + * + * @param cb the callback to run + */ + public final void setMetadataCb(CameraMetaDataCallback cb) + { + mCameraMetaDataCallback = cb; + native_setMetadataCb(cb!=null); + } + private native final void native_setMetadataCb(boolean mode); + + /** @hide + * Set camera face detection command to send meta data. + */ + public final void sendMetaData() + { + native_sendMetaData(); + } + private native final void native_sendMetaData(); + + /** @hide + * Configure longshot mode. Available only in ZSL. + * + * @param enable enable/disable this mode + */ + public final void setLongshot(boolean enable) + { + native_setLongshot(enable); + } + private native final void native_setLongshot(boolean enable); + + /** @hide + * Handles the Touch Co-ordinate. + */ + public class Coordinate { + /** + * Sets the x,y co-ordinates for a touch event + * + * @param x the x co-ordinate (pixels) + * @param y the y co-ordinate (pixels) + */ + public Coordinate(int x, int y) { + xCoordinate = x; + yCoordinate = y; + } + /** + * Compares {@code obj} to this co-ordinate. + * + * @param obj the object to compare this co-ordinate with. + * @return {@code true} if the xCoordinate and yCoordinate of {@code obj} is the + * same as those of this coordinate. {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Coordinate)) { + return false; + } + Coordinate c = (Coordinate) obj; + return xCoordinate == c.xCoordinate && yCoordinate == c.yCoordinate; + } + + /** x co-ordinate for the touch event*/ + public int xCoordinate; + + /** y co-ordinate for the touch event */ + public int yCoordinate; + }; + + /** @hide + * Returns the current focus position. + * + * If it's in AF mode, it's the lens position after af is done. + * + * If it's in Manual Focus mode, it actually returns the value + * set by user via {@link #setParameters(Camera.Parameters)}. + */ + public int getCurrentFocusPosition() { + Parameters p = new Parameters(); + String s = native_getParameters(); + p.unflatten(s); + + int focus_pos = -1; + if (p.getCurrentFocusPosition() != null) { + focus_pos = Integer.parseInt(p.getCurrentFocusPosition()); + } + return focus_pos; + } + + /* ### QC ADD-ONS: END */ /** * Returns a copied {@link Parameters}; for shim use only. * @@ -2374,6 +2627,10 @@ public class Parameters { public static final String WHITE_BALANCE_CLOUDY_DAYLIGHT = "cloudy-daylight"; public static final String WHITE_BALANCE_TWILIGHT = "twilight"; public static final String WHITE_BALANCE_SHADE = "shade"; + /** @hide + * wb manual cct mode. + */ + public static final String WHITE_BALANCE_MANUAL_CCT = "manual-cct"; // Values for color effect settings. public static final String EFFECT_NONE = "none"; @@ -2421,6 +2678,11 @@ public class Parameters { */ public static final String FLASH_MODE_TORCH = "torch"; + /** @hide + * Scene mode is off. + */ + public static final String SCENE_MODE_ASD = "asd"; + /** * Scene mode is off. */ @@ -2497,6 +2759,14 @@ public class Parameters { * Capture the naturally warm color of scenes lit by candles. */ public static final String SCENE_MODE_CANDLELIGHT = "candlelight"; + /** @hide + * SCENE_MODE_BACKLIGHT + **/ + public static final String SCENE_MODE_BACKLIGHT = "backlight"; + /** @hide + * SCENE_MODE_FLOWERS + **/ + public static final String SCENE_MODE_FLOWERS = "flowers"; /** * Applications are looking for a barcode. Camera driver will be @@ -2539,6 +2809,13 @@ public class Parameters { */ public static final String FOCUS_MODE_FIXED = "fixed"; + /** @hide + * Normal focus mode. Applications should call + * {@link #autoFocus(AutoFocusCallback)} to start the focus in this + * mode. + */ + public static final String FOCUS_MODE_NORMAL = "normal"; + /** * Extended depth of field (EDOF). Focusing is done digitally and * continuously. Applications should not call {@link @@ -2591,6 +2868,11 @@ public class Parameters { */ public static final String FOCUS_MODE_CONTINUOUS_PICTURE = "continuous-picture"; + /** @hide + * manual focus mode + */ + public static final String FOCUS_MODE_MANUAL_POSITION = "manual"; + // Indices for focus distance array. /** * The array index of near focus distance for use with @@ -2627,11 +2909,15 @@ public class Parameters { // Formats for setPreviewFormat and setPictureFormat. private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp"; private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp"; + private static final String PIXEL_FORMAT_YUV420SP_ADRENO = "yuv420sp-adreno"; private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv"; private static final String PIXEL_FORMAT_YUV420P = "yuv420p"; private static final String PIXEL_FORMAT_RGB565 = "rgb565"; private static final String PIXEL_FORMAT_JPEG = "jpeg"; private static final String PIXEL_FORMAT_BAYER_RGGB = "bayer-rggb"; + private static final String PIXEL_FORMAT_RAW = "raw"; + private static final String PIXEL_FORMAT_YV12 = "yv12"; + private static final String PIXEL_FORMAT_NV12 = "nv12"; /** * Order matters: Keys that are {@link #set(String, String) set} later @@ -3451,8 +3737,11 @@ public void setGpsProcessingMethod(String processing_method) { * parameters. */ public void removeGpsData() { + remove(KEY_QC_GPS_LATITUDE_REF); remove(KEY_GPS_LATITUDE); + remove(KEY_QC_GPS_LONGITUDE_REF); remove(KEY_GPS_LONGITUDE); + remove(KEY_QC_GPS_ALTITUDE_REF); remove(KEY_GPS_ALTITUDE); remove(KEY_GPS_TIMESTAMP); remove(KEY_GPS_PROCESSING_METHOD); @@ -3622,6 +3911,7 @@ public String getSceneMode() { * @see #getSceneMode() */ public void setSceneMode(String value) { + if(getSupportedSceneModes() == null) return; set(KEY_SCENE_MODE, value); } @@ -3659,6 +3949,7 @@ public String getFlashMode() { * @see #getFlashMode() */ public void setFlashMode(String value) { + if(getSupportedFlashModes() == null) return; set(KEY_FLASH_MODE, value); } @@ -4343,6 +4634,7 @@ private void splitInt(String str, int[] output) { splitter.setString(str); int index = 0; for (String s : splitter) { + s = s.replaceAll("\\s",""); output[index++] = Integer.parseInt(s); } } @@ -4413,7 +4705,7 @@ private Size strToSize(String str) { // Example string: "(10000,26623),(10000,30000)". Return null if the // passing string is null or the size is 0. private ArrayList splitRange(String str) { - if (str == null || str.charAt(0) != '(' + if (str == null || str.isEmpty() || str.charAt(0) != '(' || str.charAt(str.length() - 1) != ')') { Log.e(TAG, "Invalid range list string=" + str); return null; @@ -4439,7 +4731,7 @@ private ArrayList splitRange(String str) { // the passing string is null or the size is 0 or (0,0,0,0,0). @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private ArrayList splitArea(String str) { - if (str == null || str.charAt(0) != '(' + if (str == null || str.isEmpty() || str.charAt(0) != '(' || str.charAt(str.length() - 1) != ')') { Log.e(TAG, "Invalid area string=" + str); return null; @@ -4476,5 +4768,1231 @@ private boolean same(String s1, String s2) { if (s1 != null && s1.equals(s2)) return true; return false; } + /* ### QC ADD-ONS: START */ + + /* ### QC ADDED PARAMETER KEYS*/ + private static final String KEY_QC_HFR_SIZE = "hfr-size"; + private static final String KEY_QC_PREVIEW_FRAME_RATE_MODE = "preview-frame-rate-mode"; + private static final String KEY_QC_PREVIEW_FRAME_RATE_AUTO_MODE = "frame-rate-auto"; + private static final String KEY_QC_PREVIEW_FRAME_RATE_FIXED_MODE = "frame-rate-fixed"; + private static final String KEY_QC_GPS_LATITUDE_REF = "gps-latitude-ref"; + private static final String KEY_QC_GPS_LONGITUDE_REF = "gps-longitude-ref"; + private static final String KEY_QC_GPS_ALTITUDE_REF = "gps-altitude-ref"; + private static final String KEY_QC_GPS_STATUS = "gps-status"; + private static final String KEY_QC_EXIF_DATETIME = "exif-datetime"; + private static final String KEY_QC_TOUCH_AF_AEC = "touch-af-aec"; + private static final String KEY_QC_TOUCH_INDEX_AEC = "touch-index-aec"; + private static final String KEY_QC_TOUCH_INDEX_AF = "touch-index-af"; + private static final String KEY_QC_MANUAL_FOCUS_POSITION = "manual-focus-position"; + private static final String KEY_QC_MANUAL_FOCUS_POS_TYPE = "manual-focus-pos-type"; + private static final String KEY_QC_SCENE_DETECT = "scene-detect"; + private static final String KEY_QC_ISO_MODE = "iso"; + private static final String KEY_QC_EXPOSURE_TIME = "exposure-time"; + private static final String KEY_QC_MIN_EXPOSURE_TIME = "min-exposure-time"; + private static final String KEY_QC_MAX_EXPOSURE_TIME = "max-exposure-time"; + private static final String KEY_QC_LENSSHADE = "lensshade"; + private static final String KEY_QC_HISTOGRAM = "histogram"; + private static final String KEY_QC_SKIN_TONE_ENHANCEMENT = "skinToneEnhancement"; + private static final String KEY_QC_AUTO_EXPOSURE = "auto-exposure"; + private static final String KEY_QC_SHARPNESS = "sharpness"; + private static final String KEY_QC_MAX_SHARPNESS = "max-sharpness"; + private static final String KEY_QC_CONTRAST = "contrast"; + private static final String KEY_QC_MAX_CONTRAST = "max-contrast"; + private static final String KEY_QC_SATURATION = "saturation"; + private static final String KEY_QC_MAX_SATURATION = "max-saturation"; + private static final String KEY_QC_DENOISE = "denoise"; + private static final String KEY_QC_CONTINUOUS_AF = "continuous-af"; + private static final String KEY_QC_SELECTABLE_ZONE_AF = "selectable-zone-af"; + private static final String KEY_QC_FACE_DETECTION = "face-detection"; + private static final String KEY_QC_MEMORY_COLOR_ENHANCEMENT = "mce"; + private static final String KEY_QC_REDEYE_REDUCTION = "redeye-reduction"; + private static final String KEY_QC_ZSL = "zsl"; + private static final String KEY_QC_CAMERA_MODE = "camera-mode"; + private static final String KEY_QC_VIDEO_HIGH_FRAME_RATE = "video-hfr"; + private static final String KEY_QC_VIDEO_HDR = "video-hdr"; + private static final String KEY_QC_POWER_MODE = "power-mode"; + private static final String KEY_QC_POWER_MODE_SUPPORTED = "power-mode-supported"; + private static final String KEY_QC_WB_MANUAL_CCT = "wb-manual-cct"; + private static final String KEY_QC_MIN_WB_CCT = "min-wb-cct"; + private static final String KEY_QC_MAX_WB_CCT = "max-wb-cct"; + private static final String KEY_QC_AUTO_HDR_ENABLE = "auto-hdr-enable"; + private static final String KEY_QC_VIDEO_ROTATION = "video-rotation"; + + /** @hide + * KEY_QC_AE_BRACKET_HDR + **/ + public static final String KEY_QC_AE_BRACKET_HDR = "ae-bracket-hdr"; + + /* ### QC ADDED PARAMETER VALUES*/ + + // Values for touch af/aec settings. + /** @hide + * TOUCH_AF_AEC_OFF + **/ + public static final String TOUCH_AF_AEC_OFF = "touch-off"; + /** @hide + * TOUCH_AF_AEC_ON + **/ + public static final String TOUCH_AF_AEC_ON = "touch-on"; + + // Values for auto exposure settings. + /** @hide + * Auto exposure frame-avg + **/ + public static final String AUTO_EXPOSURE_FRAME_AVG = "frame-average"; + /** @hide + * Auto exposure center weighted + **/ + public static final String AUTO_EXPOSURE_CENTER_WEIGHTED = "center-weighted"; + /** @hide + * Auto exposure spot metering + **/ + public static final String AUTO_EXPOSURE_SPOT_METERING = "spot-metering"; + + //Values for ISO settings + /** @hide + * ISO_AUTO + **/ + public static final String ISO_AUTO = "auto"; + /** @hide + * ISO_HJR + **/ + public static final String ISO_HJR = "ISO_HJR"; + /** @hide + * ISO_100 + **/ + public static final String ISO_100 = "ISO100"; + /** @hide + * ISO_200 + **/ + public static final String ISO_200 = "ISO200"; + /** @hide + * ISO_400 + **/ + public static final String ISO_400 = "ISO400"; + /** @hide + * ISO_800 + **/ + public static final String ISO_800 = "ISO800"; + /** @hide + * ISO_1600 + **/ + public static final String ISO_1600 = "ISO1600"; + + /** @hide + * ISO_3200 + **/ + public static final String ISO_3200 = "ISO3200"; + + //Values for Lens Shading + /** @hide + * LENSSHADE_ENABLE + **/ + public static final String LENSSHADE_ENABLE = "enable"; + /** @hide + * LENSSHADE_DISABLE + **/ + public static final String LENSSHADE_DISABLE= "disable"; + + //Values for Histogram + /** @hide + * Histogram enable + **/ + public static final String HISTOGRAM_ENABLE = "enable"; + /** @hide + * Histogram disable + **/ + public static final String HISTOGRAM_DISABLE= "disable"; + + //Values for Skin Tone Enhancement + /** @hide + * SKIN_TONE_ENHANCEMENT_ENABLE + **/ + public static final String SKIN_TONE_ENHANCEMENT_ENABLE = "enable"; + /** @hide + * SKIN_TONE_ENHANCEMENT_DISABLE + **/ + public static final String SKIN_TONE_ENHANCEMENT_DISABLE= "disable"; + + // Values for MCE settings. + /** @hide + * MCE_ENaBLE + **/ + public static final String MCE_ENABLE = "enable"; + /** @hide + * MCE_DISABLE + **/ + public static final String MCE_DISABLE = "disable"; + + // Values for ZSL settings. + /** @hide + * ZSL_ON + **/ + public static final String ZSL_ON = "on"; + /** @hide + * ZSL_OFF + **/ + public static final String ZSL_OFF = "off"; + + // Values for HDR Bracketing settings. + + /** @hide + * AEC bracketing off + **/ + public static final String AE_BRACKET_HDR_OFF = "Off"; + /** @hide + * AEC bracketing hdr + **/ + public static final String AE_BRACKET_HDR = "HDR"; + /** @hide + * AEC bracketing aec-bracket + **/ + public static final String AE_BRACKET = "AE-Bracket"; + + // Values for Power mode. + /** @hide + * LOW_POWER + **/ + public static final String LOW_POWER = "Low_Power"; + /** @hide + * NORMAL_POWER + **/ + public static final String NORMAL_POWER = "Normal_Power"; + + // Values for HFR settings. + /** @hide + * VIDEO_HFR_OFF + **/ + public static final String VIDEO_HFR_OFF = "off"; + /** @hide + * VIDEO_HFR_2X + **/ + public static final String VIDEO_HFR_2X = "60"; + /** @hide + * VIDEO_HFR_3X + **/ + public static final String VIDEO_HFR_3X = "90"; + /** @hide + * VIDEO_HFR_4X + **/ + public static final String VIDEO_HFR_4X = "120"; + + // Values for auto scene detection settings. + /** @hide + * SCENE_DETECT_OFF + **/ + public static final String SCENE_DETECT_OFF = "off"; + /** @hide + * SCENE_DETECT_ON + **/ + public static final String SCENE_DETECT_ON = "on"; + + //Values for Continuous AF + + /** @hide + * CAF off + **/ + public static final String CONTINUOUS_AF_OFF = "caf-off"; + /** @hide + * CAF on + **/ + public static final String CONTINUOUS_AF_ON = "caf-on"; + /** @hide + * Denoise off + **/ + public static final String DENOISE_OFF = "denoise-off"; + /** @hide + * Denoise on + **/ + public static final String DENOISE_ON = "denoise-on"; + + // Values for Redeye Reduction settings. + /** @hide + * REDEYE_REDUCTION_ENABLE + **/ + public static final String REDEYE_REDUCTION_ENABLE = "enable"; + /** @hide + * REDEYE_REDUCTION_DISABLE + **/ + public static final String REDEYE_REDUCTION_DISABLE = "disable"; + + // Values for selectable zone af settings. + /** @hide + * SELECTABLE_ZONE_AF_AUTO + **/ + public static final String SELECTABLE_ZONE_AF_AUTO = "auto"; + /** @hide + * SELECTABLE_ZONE_AF_SPOTMETERING + **/ + public static final String SELECTABLE_ZONE_AF_SPOTMETERING = "spot-metering"; + /** @hide + * SELECTABLE_ZONE_AF_CENTER_WEIGHTED + **/ + public static final String SELECTABLE_ZONE_AF_CENTER_WEIGHTED = "center-weighted"; + /** @hide + * SELECTABLE_ZONE_AF_FRAME_AVERAGE + **/ + public static final String SELECTABLE_ZONE_AF_FRAME_AVERAGE = "frame-average"; + + // Values for Face Detection settings. + /** @hide + * Face Detection off + **/ + public static final String FACE_DETECTION_OFF = "off"; + /** @hide + * Face Detction on + **/ + public static final String FACE_DETECTION_ON = "on"; + + // Values for video rotation settings. + + /** @hide + * VIDEO_ROTATION_0 + **/ + public static final String VIDEO_ROTATION_0 = "0"; + /** @hide + * VIDEO_ROTATION_90 + **/ + public static final String VIDEO_ROTATION_90 = "90"; + /** @hide + * VIDEO_ROTATION_180 + **/ + public static final String VIDEO_ROTATION_180 = "180"; + /** @hide + * VIDEO_ROTATION_270 + **/ + public static final String VIDEO_ROTATION_270 = "270"; + + /* ### QC ADDED PARAMETER APIS*/ + /** @hide + * Gets the supported preview sizes in high frame rate recording mode. + * + * @return a list of Size object. This method will always return a list + * with at least one element. + */ + public List getSupportedHfrSizes() { + String str = get(KEY_QC_HFR_SIZE + SUPPORTED_VALUES_SUFFIX); + return splitSize(str); + } + + /** @hide + * Gets the supported Touch AF/AEC setting. + * + * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC + * setting is not supported. + * + */ + public List getSupportedTouchAfAec() { + String str = get(KEY_QC_TOUCH_AF_AEC + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** + * Gets the supported Touch AF/AEC setting. + * + * @return a List of TOUCH_AF_AEC_XXX string constants. null if TOUCH AF/AEC + * setting is not supported. + * + */ + + /** @hide + * Gets the supported frame rate modes. + * + * @return a List of FRAME_RATE_XXX_MODE string constant. null if this + * setting is not supported. + */ + public List getSupportedPreviewFrameRateModes() { + String str = get(KEY_QC_PREVIEW_FRAME_RATE_MODE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported auto scene detection modes. + * + * @return a List of SCENE_DETECT_XXX string constant. null if scene detection + * setting is not supported. + * + */ + public List getSupportedSceneDetectModes() { + String str = get(KEY_QC_SCENE_DETECT + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported ISO values. + * + * @return a List of FLASH_MODE_XXX string constants. null if flash mode + * setting is not supported. + */ + public List getSupportedIsoValues() { + String str = get(KEY_QC_ISO_MODE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported Lensshade modes. + * + * @return a List of LENS_MODE_XXX string constants. null if lens mode + * setting is not supported. + */ + public List getSupportedLensShadeModes() { + String str = get(KEY_QC_LENSSHADE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported Histogram modes. + * + * @return a List of HISTOGRAM_XXX string constants. null if histogram mode + * setting is not supported. + */ + public List getSupportedHistogramModes() { + String str = get(KEY_QC_HISTOGRAM + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported Skin Tone Enhancement modes. + * + * @return a List of SKIN_TONE_ENHANCEMENT_XXX string constants. null if skin tone enhancement + * setting is not supported. + */ + public List getSupportedSkinToneEnhancementModes() { + String str = get(KEY_QC_SKIN_TONE_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported auto exposure setting. + * + * @return a List of AUTO_EXPOSURE_XXX string constants. null if auto exposure + * setting is not supported. + */ + public List getSupportedAutoexposure() { + String str = get(KEY_QC_AUTO_EXPOSURE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported MCE modes. + * + * @return a List of MCE_ENABLE/DISABLE string constants. null if MCE mode + * setting is not supported. + */ + public List getSupportedMemColorEnhanceModes() { + String str = get(KEY_QC_MEMORY_COLOR_ENHANCEMENT + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported ZSL modes. + * + * @return a List of ZSL_OFF/OFF string constants. null if ZSL mode + * setting is not supported. + */ + public List getSupportedZSLModes() { + String str = get(KEY_QC_ZSL + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported Video HDR modes. + * + * @return a List of Video HDR_OFF/OFF string constants. null if + * Video HDR mode setting is not supported. + */ + public List getSupportedVideoHDRModes() { + String str = get(KEY_QC_VIDEO_HDR + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported HFR modes. + * + * @return a List of VIDEO_HFR_XXX string constants. null if hfr mode + * setting is not supported. + */ + public List getSupportedVideoHighFrameRateModes() { + String str = get(KEY_QC_VIDEO_HIGH_FRAME_RATE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported Continuous AF modes. + * + * @return a List of CONTINUOUS_AF_XXX string constant. null if continuous AF + * setting is not supported. + * + */ + public List getSupportedContinuousAfModes() { + String str = get(KEY_QC_CONTINUOUS_AF + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported DENOISE modes. + * + * @return a List of DENOISE_XXX string constant. null if DENOISE + * setting is not supported. + * + */ + public List getSupportedDenoiseModes() { + String str = get(KEY_QC_DENOISE + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported selectable zone af setting. + * + * @return a List of SELECTABLE_ZONE_AF_XXX string constants. null if selectable zone af + * setting is not supported. + */ + public List getSupportedSelectableZoneAf() { + String str = get(KEY_QC_SELECTABLE_ZONE_AF + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported face detection modes. + * + * @return a List of FACE_DETECTION_XXX string constant. null if face detection + * setting is not supported. + * + */ + public List getSupportedFaceDetectionModes() { + String str = get(KEY_QC_FACE_DETECTION + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Gets the supported redeye reduction modes. + * + * @return a List of REDEYE_REDUCTION_XXX string constant. null if redeye reduction + * setting is not supported. + * + */ + public List getSupportedRedeyeReductionModes() { + String str = get(KEY_QC_REDEYE_REDUCTION + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + /** @hide + * Sets GPS altitude reference. This will be stored in JPEG EXIF header. + * @param altRef reference GPS altitude in meters. + */ + public void setGpsAltitudeRef(double altRef) { + set(KEY_QC_GPS_ALTITUDE_REF, Double.toString(altRef)); + } + + /** @hide + * Sets GPS Status. This will be stored in JPEG EXIF header. + * + * @param status GPS status (UTC in seconds since January 1, + * 1970). + */ + public void setGpsStatus(double status) { + set(KEY_QC_GPS_STATUS, Double.toString(status)); + } + + /** @hide + * Sets the touch co-ordinate for Touch AEC. + * + * @param x the x co-ordinate of the touch event + * @param y the y co-ordinate of the touch event + * + */ + public void setTouchIndexAec(int x, int y) { + String v = Integer.toString(x) + "x" + Integer.toString(y); + set(KEY_QC_TOUCH_INDEX_AEC, v); + } + + /** @hide + * Returns the touch co-ordinates of the touch event. + * + * @return a Index object with the x and y co-ordinated + * for the touch event + * + */ + public Coordinate getTouchIndexAec() { + String pair = get(KEY_QC_TOUCH_INDEX_AEC); + return strToCoordinate(pair); + } + + /** @hide + * Sets the touch co-ordinate for Touch AF. + * + * @param x the x co-ordinate of the touch event + * @param y the y co-ordinate of the touch event + * + */ + public void setTouchIndexAf(int x, int y) { + String v = Integer.toString(x) + "x" + Integer.toString(y); + set(KEY_QC_TOUCH_INDEX_AF, v); + } + + /** @hide + * Returns the touch co-ordinates of the touch event. + * + * @return a Index object with the x and y co-ordinated + * for the touch event + * + */ + public Coordinate getTouchIndexAf() { + String pair = get(KEY_QC_TOUCH_INDEX_AF); + return strToCoordinate(pair); + } + /** @hide + * Set Sharpness Level + * + * @param sharpness level + */ + public void setSharpness(int sharpness){ + if((sharpness < 0) || (sharpness > getMaxSharpness()) ) + throw new IllegalArgumentException( + "Invalid Sharpness " + sharpness); + + set(KEY_QC_SHARPNESS, String.valueOf(sharpness)); + } + + /** @hide + * Set Contrast Level + * + * @param contrast level + */ + public void setContrast(int contrast){ + if((contrast < 0 ) || (contrast > getMaxContrast())) + throw new IllegalArgumentException( + "Invalid Contrast " + contrast); + + set(KEY_QC_CONTRAST, String.valueOf(contrast)); + } + + /** @hide + * Set Saturation Level + * + * @param saturation level + */ + public void setSaturation(int saturation){ + if((saturation < 0 ) || (saturation > getMaxSaturation())) + throw new IllegalArgumentException( + "Invalid Saturation " + saturation); + + set(KEY_QC_SATURATION, String.valueOf(saturation)); + } + + /** @hide + * @return true if full size video snapshot is supported. + */ + public boolean isPowerModeSupported() { + String str = get(KEY_QC_POWER_MODE_SUPPORTED); + return TRUE.equals(str); + } + + /** @hide + * Get Sharpness level + * + * @return sharpness level + */ + public int getSharpness(){ + return getInt(KEY_QC_SHARPNESS); + } + + /** @hide + * Get Max Sharpness Level + * + * @return max sharpness level + */ + public int getMaxSharpness(){ + return getInt(KEY_QC_MAX_SHARPNESS); + } + + /** @hide + * Get Contrast level + * + * @return contrast level + */ + public int getContrast(){ + return getInt(KEY_QC_CONTRAST); + } + + /** @hide + * Get Max Contrast Level + * + * @return max contrast level + */ + public int getMaxContrast(){ + return getInt(KEY_QC_MAX_CONTRAST); + } + + /** @hide + * Get Saturation level + * + * @return saturation level + */ + public int getSaturation(){ + return getInt(KEY_QC_SATURATION); + } + + /** @hide + * Get Max Saturation Level + * + * @return max contrast level + */ + public int getMaxSaturation(){ + return getInt(KEY_QC_MAX_SATURATION); + } + + /** @hide + * Sets GPS latitude reference coordinate. This will be stored in JPEG EXIF + * header. + * @param latRef GPS latitude reference coordinate. + */ + public void setGpsLatitudeRef(String latRef) { + set(KEY_QC_GPS_LATITUDE_REF, latRef); + } + + /** @hide + * Sets GPS longitude reference coordinate. This will be stored in JPEG EXIF + * header. + * @param lonRef GPS longitude reference coordinate. + */ + public void setGpsLongitudeRef(String lonRef) { + set(KEY_QC_GPS_LONGITUDE_REF, lonRef); + } + + /** @hide + * Sets system timestamp. This will be stored in JPEG EXIF header. + * + * @param dateTime current timestamp (UTC in seconds since January 1, + * 1970). + */ + public void setExifDateTime(String dateTime) { + set(KEY_QC_EXIF_DATETIME, dateTime); + } + + /** @hide + * Gets the current Touch AF/AEC setting. + * + * @return one of TOUCH_AF_AEC_XXX string constant. null if Touch AF/AEC + * setting is not supported. + * + */ + public String getTouchAfAec() { + return get(KEY_QC_TOUCH_AF_AEC); + } + + /** @hide + * Sets the current TOUCH AF/AEC setting. + * + * @param value TOUCH_AF_AEC_XXX string constants. + * + */ + public void setTouchAfAec(String value) { + set(KEY_QC_TOUCH_AF_AEC, value); + } + + /** @hide + * Gets the current redeye reduction setting. + * + * @return one of REDEYE_REDUCTION_XXX string constant. null if redeye reduction + * setting is not supported. + * + */ + public String getRedeyeReductionMode() { + return get(KEY_QC_REDEYE_REDUCTION); + } + + /** @hide + * Sets the redeye reduction. Other parameters may be changed after changing + * redeye reduction. After setting redeye reduction, + * applications should call getParameters to know if some parameters are + * changed. + * + * @param value REDEYE_REDUCTION_XXX string constants. + * + */ + public void setRedeyeReductionMode(String value) { + set(KEY_QC_REDEYE_REDUCTION, value); + } + + /** @hide + * Gets the frame rate mode setting. + * + * @return one of FRAME_RATE_XXX_MODE string constant. null if this + * setting is not supported. + */ + public String getPreviewFrameRateMode() { + return get(KEY_QC_PREVIEW_FRAME_RATE_MODE); + } + + /** @hide + * Sets the frame rate mode. + * + * @param value FRAME_RATE_XXX_MODE string constants. + */ + public void setPreviewFrameRateMode(String value) { + set(KEY_QC_PREVIEW_FRAME_RATE_MODE, value); + } + + /** @hide + * Gets the current auto scene detection setting. + * + * @return one of SCENE_DETECT_XXX string constant. null if auto scene detection + * setting is not supported. + * + */ + public String getSceneDetectMode() { + return get(KEY_QC_SCENE_DETECT); + } + + /** @hide + * Sets the auto scene detect. Other parameters may be changed after changing + * scene detect. After setting auto scene detection, + * applications should call getParameters to know if some parameters are + * changed. + * + * @param value SCENE_DETECT_XXX string constants. + * + */ + public void setSceneDetectMode(String value) { + set(KEY_QC_SCENE_DETECT, value); + } + + /** @hide + * Gets the current hdr bracketing mode setting. + * + * @return current hdr bracketing mode. + * @see #KEY_AE_BRACKET_OFF + * @see #KEY_AE_BRACKET_HDR + * @see #KEY_AE_BRACKET_BRACKATING + */ + public String getAEBracket() { + return get(KEY_QC_AE_BRACKET_HDR); + } + + /** @hide + * Sets the Power mode. + * + * @param value Power mode. + * @see #getPowerMode() + */ + public void setPowerMode(String value) { + set(KEY_QC_POWER_MODE, value); + } + + /** @hide + * Gets the current power mode setting. + * + * @return current power mode. null if power mode setting is not + * supported. + * @see #POWER_MODE_LOW + * @see #POWER_MODE_NORMAL + */ + public String getPowerMode() { + return get(KEY_QC_POWER_MODE); + } + + /** @hide + * Set HDR-Bracketing Level + * + * @param value HDR-Bracketing + */ + public void setAEBracket(String value){ + set(KEY_QC_AE_BRACKET_HDR, value); + } + + /** @hide + * Gets the current ISO setting. + * + * @return one of ISO_XXX string constant. null if ISO + * setting is not supported. + */ + public String getISOValue() { + return get(KEY_QC_ISO_MODE); + } + + /** @hide + * Sets the ISO. + * + * @param iso ISO_XXX string constant. + */ + public void setISOValue(String iso) { + set(KEY_QC_ISO_MODE, iso); + } + + /** @hide + * Sets the exposure time. + * + * @param value exposure time. + */ + public void setExposureTime(int value) { + set(KEY_QC_EXPOSURE_TIME, Integer.toString(value)); + } + + /** @hide + * Gets the current exposure time. + * + * @return exposure time. + */ + public String getExposureTime() { + return get(KEY_QC_EXPOSURE_TIME); + } + + /** @hide + * Gets the min supported exposure time. + * + * @return min supported exposure time. + */ + public String getMinExposureTime() { + return get(KEY_QC_MIN_EXPOSURE_TIME); + } + + /** @hide + * Gets the max supported exposure time. + * + * @return max supported exposure time. + */ + public String getMaxExposureTime() { + return get(KEY_QC_MAX_EXPOSURE_TIME); + } + + /** @hide + * Gets the current LensShade Mode. + * + * @return LensShade Mode + */ + public String getLensShade() { + return get(KEY_QC_LENSSHADE); + } + + /** @hide + * Sets the current LensShade Mode. + * + * @return LensShade Mode + */ + public void setLensShade(String lensshade) { + set(KEY_QC_LENSSHADE, lensshade); + } + + /** @hide + * Gets the current auto exposure setting. + * + * @return one of AUTO_EXPOSURE_XXX string constant. null if auto exposure + * setting is not supported. + */ + public String getAutoExposure() { + return get(KEY_QC_AUTO_EXPOSURE); + } + + /** @hide + * Sets the current auto exposure setting. + * + * @param value AUTO_EXPOSURE_XXX string constants. + */ + public void setAutoExposure(String value) { + set(KEY_QC_AUTO_EXPOSURE, value); + } + + /** @hide + * Gets the current MCE Mode. + * + * @return MCE value + */ + public String getMemColorEnhance() { + return get(KEY_QC_MEMORY_COLOR_ENHANCEMENT); + } + + /** @hide + * Sets the current MCE Mode. + * + * @return MCE Mode + */ + public void setMemColorEnhance(String mce) { + set(KEY_QC_MEMORY_COLOR_ENHANCEMENT, mce); + } + + /** @hide + * Set white balance manual cct value. + * + * @param cct user CCT setting. + */ + public void setWBManualCCT(int cct) { + set(KEY_QC_WB_MANUAL_CCT, Integer.toString(cct)); + } + + /** @hide + * Gets the WB min supported CCT. + * + * @return min cct value. + */ + public String getWBMinCCT() { + return get(KEY_QC_MIN_WB_CCT); + } + + /** @hide + * Gets the WB max supported CCT. + * + * @return max cct value. + */ + public String getMaxWBCCT() { + return get(KEY_QC_MAX_WB_CCT); + } + + /** @hide + * Gets the current WB CCT. + * + * @return CCT value + */ + public String getWBCurrentCCT() { + return get(KEY_QC_WB_MANUAL_CCT); + } + + /** @hide + * Gets the current ZSL Mode. + * + * @return ZSL mode value + */ + public String getZSLMode() { + return get(KEY_QC_ZSL); + } + + /** @hide + * Sets the current ZSL Mode. ZSL mode is set as a 0th bit in KEY_CAMERA_MODE. + * + * @return null + */ + public void setZSLMode(String zsl) { + set(KEY_QC_ZSL, zsl); + } + + /** @hide + * Sets the current Auto HDR Mode. + * @ auto_hdr auto hdr string for enable/disable + * @return null + */ + public void setAutoHDRMode(String auto_hdr){ + set(KEY_QC_AUTO_HDR_ENABLE,auto_hdr); + } + + /** @hide + * Gets the current Camera Mode Flag. Camera mode includes a + * flag(byte) which indicates different camera modes. + * For now support for ZSL added at bit0 + * + * @return Camera Mode. + */ + public String getCameraMode() { + return get(KEY_QC_CAMERA_MODE); + } + + /** @hide + * Sets the current Camera Mode. + * + * @return null + */ + public void setCameraMode(int cameraMode) { + set(KEY_QC_CAMERA_MODE, cameraMode); + } + + private static final int MANUAL_FOCUS_POS_TYPE_INDEX = 0; + private static final int MANUAL_FOCUS_POS_TYPE_DAC = 1; + /** @hide + * Set focus position. + * + * @param pos user setting of focus position. + */ + public void setFocusPosition(int type, int pos) { + set(KEY_QC_MANUAL_FOCUS_POS_TYPE, Integer.toString(type)); + set(KEY_QC_MANUAL_FOCUS_POSITION, Integer.toString(pos)); + } + + /** @hide + * Gets the current focus position. + * + * @return current focus position + */ + public String getCurrentFocusPosition() { + return get(KEY_QC_MANUAL_FOCUS_POSITION); + } + + + /** @hide + * Gets the current HFR Mode. + * + * @return VIDEO_HFR_XXX string constants + */ + public String getVideoHighFrameRate() { + return get(KEY_QC_VIDEO_HIGH_FRAME_RATE); + } + + /** @hide + * Sets the current HFR Mode. + * + * @param hfr VIDEO_HFR_XXX string constants + */ + public void setVideoHighFrameRate(String hfr) { + set(KEY_QC_VIDEO_HIGH_FRAME_RATE, hfr); + } + + /** @hide + * Gets the current Video HDR Mode. + * + * @return Video HDR mode value + */ + public String getVideoHDRMode() { + return get(KEY_QC_VIDEO_HDR); + } + + /** @hide + * Sets the current Video HDR Mode. + * + * @return null + */ + public void setVideoHDRMode(String videohdr) { + set(KEY_QC_VIDEO_HDR, videohdr); + } + + /** @hide + * Gets the current DENOISE setting. + * + * @return one of DENOISE_XXX string constant. null if Denoise + * setting is not supported. + * + */ + public String getDenoise() { + return get(KEY_QC_DENOISE); + } + + /** @hide + * Gets the current Continuous AF setting. + * + * @return one of CONTINUOUS_AF_XXX string constant. null if continuous AF + * setting is not supported. + * + */ + public String getContinuousAf() { + return get(KEY_QC_CONTINUOUS_AF); + } + + /** @hide + * Sets the current Denoise mode. + * @param value DENOISE_XXX string constants. + * + */ + + public void setDenoise(String value) { + set(KEY_QC_DENOISE, value); + } + + /** @hide + * Sets the current Continuous AF mode. + * @param value CONTINUOUS_AF_XXX string constants. + * + */ + public void setContinuousAf(String value) { + set(KEY_QC_CONTINUOUS_AF, value); + } + + /** @hide + * Gets the current selectable zone af setting. + * + * @return one of SELECTABLE_ZONE_AF_XXX string constant. null if selectable zone af + * setting is not supported. + */ + public String getSelectableZoneAf() { + return get(KEY_QC_SELECTABLE_ZONE_AF); + } + + /** @hide + * Sets the current selectable zone af setting. + * + * @param value SELECTABLE_ZONE_AF_XXX string constants. + */ + public void setSelectableZoneAf(String value) { + set(KEY_QC_SELECTABLE_ZONE_AF, value); + } + + /** @hide + * Gets the current face detection setting. + * + * @return one of FACE_DETECTION_XXX string constant. null if face detection + * setting is not supported. + * + */ + public String getFaceDetectionMode() { + return get(KEY_QC_FACE_DETECTION); + } + + /** @hide + * Sets the auto scene detect. Other settings like Touch AF/AEC might be + * changed after setting face detection. + * + * @param value FACE_DETECTION_XXX string constants. + * + */ + public void setFaceDetectionMode(String value) { + set(KEY_QC_FACE_DETECTION, value); + } + + /** @hide + * Gets the current video rotation setting. + * + * @return one of VIDEO_QC_ROTATION_XXX string constant. null if video rotation + * setting is not supported. + */ + public String getVideoRotation() { + return get(KEY_QC_VIDEO_ROTATION); + } + + /** @hide + * Sets the current video rotation setting. + * + * @param value VIDEO_QC_ROTATION_XXX string constants. + */ + public void setVideoRotation(String value) { + set(KEY_QC_VIDEO_ROTATION, value); + } + /** @hide + * Gets the supported video rotation modes. + * + * @return a List of VIDEO_QC_ROTATION_XXX string constant. null if this + * setting is not supported. + */ + public List getSupportedVideoRotationValues() { + String str = get(KEY_QC_VIDEO_ROTATION + SUPPORTED_VALUES_SUFFIX); + return split(str); + } + + // Splits a comma delimited string to an ArrayList of Coordinate. + // Return null if the passing string is null or the Coordinate is 0. + private ArrayList splitCoordinate(String str) { + if (str == null) return null; + TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); + splitter.setString(str); + ArrayList coordinateList = new ArrayList(); + for (String s : splitter) { + Coordinate coordinate = strToCoordinate(s); + if (coordinate != null) coordinateList.add(coordinate); + } + if (coordinateList.size() == 0) return null; + return coordinateList; + } + + // Parses a string (ex: "500x500") to Coordinate object. + // Return null if the passing string is null. + private Coordinate strToCoordinate(String str) { + if (str == null) return null; + + int pos = str.indexOf('x'); + if (pos != -1) { + String x = str.substring(0, pos); + String y = str.substring(pos + 1); + return new Coordinate(Integer.parseInt(x), + Integer.parseInt(y)); + } + Log.e(TAG, "Invalid Coordinate parameter string=" + str); + return null; + } + /* ### QC ADD-ONS: END */ }; } diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 8f6a23dc389a7..1c14f12dbab67 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -29,15 +29,20 @@ import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.MemoryFile; import android.os.MessageQueue; +import android.provider.Settings; +import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -56,6 +61,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * Sensor manager implementation that communicates with the built-in @@ -145,6 +152,10 @@ private static native int nativeSetOperationParameter( private Optional mHasHighSamplingRateSensorsPermission = Optional.empty(); + private String mBlockedPackageList; + private final Set mBlockedApps = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + /** @hide */ public SystemSensorManager(Context context, Looper mainLooper) { synchronized (sLock) { @@ -172,6 +183,12 @@ public SystemSensorManager(Context context, Looper mainLooper) { mHandleToSensor.put(sensor.getHandle(), sensor); } } + + parsePackageList(); + + SettingsObserver observer = new SettingsObserver( + new Handler(mMainLooper)); + observer.observe(); } /** @hide */ @@ -252,6 +269,76 @@ protected List getFullDynamicSensorList() { return mFullDynamicSensorsList; } + private void parsePackageList() { + String blockedApp = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.SENSOR_BLOCKED_APP); + if (blockedApp == null) { + blockedApp = TextUtils.join("|", mContext.getResources().getStringArray( + com.android.internal.R.array.config_blockPackagesSensorDrain)); + } + splitAndAddToArrayList(blockedApp, "\\|"); + } + + private void savePackageList(ArrayList arrayList) { + String setting = Settings.Global.SENSOR_BLOCKED_APP; + + List settings = new ArrayList(); + for (String app : arrayList) { + settings.add(app.toString()); + } + final String value = TextUtils.join("|", settings); + if (TextUtils.equals(setting, Settings.Global.SENSOR_BLOCKED_APP)) { + mBlockedPackageList = value; + } + Settings.Global.putString(mContext.getContentResolver(), + setting, value); + } + + private void addBlockedApp(String packageName) { + if (mBlockedApps.add(packageName)) { + savePackageList(new ArrayList<>(mBlockedApps)); + } + } + + private boolean isBlockedApp(String packageName) { + return mBlockedApps.contains(packageName); + } + + public void notePackageUninstalled(String pkgName) { + if (mBlockedApps.remove(pkgName)) { + savePackageList(new ArrayList<>(mBlockedApps)); + } + } + + private void splitAndAddToArrayList(String baseString, String separator) { + mBlockedApps.clear(); + if (baseString != null) { + for (String s : TextUtils.split(baseString, separator)) { + final String v = s.trim(); + if (!v.isEmpty()) mBlockedApps.add(v); + } + } + } + + class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.SENSOR_BLOCKED_APP), false, this); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.SENSOR_BLOCK), false, this); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + parsePackageList(); + } + } + /** @hide */ @Override protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, @@ -269,6 +356,21 @@ protected boolean registerListenerImpl(SensorEventListener listener, Sensor sens Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative"); return false; } + + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.SENSOR_BLOCK, 0) == 1) { + int sensortype = sensor.getType(); + if (sensortype == Sensor.TYPE_SIGNIFICANT_MOTION || + sensortype == Sensor.TYPE_ACCELEROMETER || + sensortype == Sensor.TYPE_LINEAR_ACCELERATION) { + String pkgName = mContext.getPackageName(); + if (isBlockedApp(pkgName)) { + Log.w(TAG, "Preventing " + pkgName + " from using " + sensor.getStringType()); + return false; + } + } + } + if (mSensorListeners.size() >= MAX_LISTENER_COUNT) { Log.e(TAG, "Too many sensor listeners! Dump:"); Map listenerCounts = new HashMap<>(); @@ -350,6 +452,20 @@ protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; + if (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.SENSOR_BLOCK, 0) == 1) { + final int sensortype = sensor.getType(); + if (sensortype == Sensor.TYPE_SIGNIFICANT_MOTION || + sensortype == Sensor.TYPE_ACCELEROMETER || + sensortype == Sensor.TYPE_LINEAR_ACCELERATION) { + final String pkgName = mContext.getPackageName(); + if (isBlockedApp(pkgName)) { + Log.w(TAG, "Preventing " + pkgName + " from using " + sensor.getStringType()); + return false; + } + } + } + if (mTriggerListeners.size() >= MAX_LISTENER_COUNT) { throw new IllegalStateException("request failed, " + "the trigger listeners size has exceeded the maximum limit " diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index affc5004403c0..08c39961aa3ba 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -1404,6 +1404,10 @@ public abstract CaptureRequest.Builder createReprocessCaptureRequest( @Override public abstract void close(); + /** @hide */ + public abstract void setVendorStreamConfigMode(int index) + throws CameraAccessException; + /** * Checks whether a particular {@link SessionConfiguration} is supported by the camera device. * diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 5cd5ecd7beda7..204413bedc028 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -2487,8 +2487,11 @@ private String[] extractCameraIdListLocked(int deviceId, int devicePolicy) { try { List cameraIds = new ArrayList<>(); boolean exposeAuxCamera = Camera.shouldExposeAuxCamera(); - for (int i = 0; i < mDeviceStatus.size(); i++) { - if (!exposeAuxCamera && i == 2) break; + int size = exposeAuxCamera ? mDeviceStatus.size() : 2; + if (mDeviceStatus.size() < size) { + size = mDeviceStatus.size(); + } + for (int i = 0; i < size; i++) { int status = mDeviceStatus.valueAt(i); DeviceCameraInfo info = mDeviceStatus.keyAt(i); if (status == ICameraServiceListener.STATUS_NOT_PRESENT @@ -2538,6 +2541,12 @@ private Set> extractConcurrentCameraIdListLocked(int deviceId, } private static void sortCameraIds(String[] cameraIds) { + // Check if the cameraIds array is null to avoid NullPointerException + if (cameraIds == null) { + Log.e("CameraManagerGlobal", "Camera ID array is null"); + return; + } + // The sort logic must match the logic in // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds Arrays.sort(cameraIds, new Comparator() { @@ -2875,6 +2884,14 @@ public int getTorchStrengthLevel( throw new IllegalArgumentException("cameraId was null"); } + /* Force to expose only two cameras + * if the package name does not falls in this bucket + */ + boolean exposeAuxCamera = Camera.shouldExposeAuxCamera(); + if (exposeAuxCamera == false && (Integer.parseInt(cameraId) >= 2)) { + throw new IllegalArgumentException("invalid cameraId"); + } + ICameraService cameraService = getCameraService(); if (cameraService == null) { throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, @@ -3238,6 +3255,15 @@ private void onTorchStatusChangedLocked(int status, DeviceCameraInfo info) { info.mCameraId, status, info.mDeviceId)); } + /* Force to ignore the aux or composite camera torch status update + * if the package name does not falls in this bucket + */ + boolean exposeAuxCamera = Camera.shouldExposeAuxCamera(); + if (exposeAuxCamera == false && Integer.parseInt(info.mCameraId) >= 2) { + Log.w(TAG, "ignore the torch status update of camera: " + info.mCameraId); + return; + } + if (!validTorchStatus(status)) { Log.e(TAG, String.format( "Ignoring invalid camera %s torch status 0x%x for device %d", diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java index 618044123d7c0..f4fd2f0839fae 100644 --- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java @@ -15,6 +15,7 @@ */ package android.hardware.camera2.impl; +import android.app.ActivityThread; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraDevice; @@ -28,6 +29,7 @@ import android.os.Binder; import android.os.Handler; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.Log; import android.view.Surface; @@ -131,6 +133,18 @@ public class CameraCaptureSessionImpl extends CameraCaptureSession Log.e(TAG, mIdString + "Failed to create capture session; configuration failed"); mConfigureSuccess = false; } + + setSkipUnconfigure(); + } + + private void setSkipUnconfigure() { + String packageName = ActivityThread.currentOpPackageName(); + List packageList = Arrays.asList(SystemProperties.get( + "vendor.camera.skip_unconfigure.packagelist", packageName).split(",")); + + if (packageList.contains(packageName)) { + mSkipUnconfigure = true; + } } @Override diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java index 87553d8c42ab2..bbac7e3796153 100644 --- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java @@ -26,11 +26,13 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; +import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.utils.SurfaceUtils; import android.os.Handler; import android.os.ConditionVariable; import android.util.Range; import android.util.Log; +import android.util.Size; import android.view.Surface; import java.util.ArrayList; @@ -118,7 +120,7 @@ public List createHighSpeedRequestList(CaptureRequest request) } Log.v(TAG, "previewFps: " + previewFps); - int requestListSize = fpsRange.getUpper() / previewFps; + int requestListSize = getHighSpeedRequestListSize(fpsRange, outputSurfaces); // If it's a preview, keep requestList size fixed = 1. if (fpsRange.getUpper() > fpsRange.getLower()) { requestListSize = 1; @@ -203,6 +205,34 @@ private boolean isConstrainedHighSpeedRequestList(List requestLi return true; } + private int getHighSpeedRequestListSize(Range fpsRange, Collection surfaces) { + int requestListSize = 0; + + for (Surface surface : surfaces) { + + if (SurfaceUtils.isSurfaceForHwVideoEncoder(surface)) { + Size surfaceSize = SurfaceUtils.getSurfaceSize(surface); + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = + mCharacteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS); + + // Get the batchsize for matching FPS & video size + for (HighSpeedVideoConfiguration config : highSpeedVideoConfigurations) { + if (config.getSize().equals(surfaceSize) && config.getFpsRange().equals(fpsRange)) { + requestListSize = config.getBatchSizeMax(); + break; + } + } + break; + } + } + + if (requestListSize == 0) { + // If cant' find the matching batch size, limit the preview to 30fps. + requestListSize = fpsRange.getUpper() / 30; + } + return requestListSize; + } + @Override public CameraDevice getDevice() { return mSessionImpl.getDevice(); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 545be8f104e40..9de7bcad41fa7 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -114,6 +114,8 @@ public Thread newThread(Runnable r) { private static final int REQUEST_ID_NONE = -1; + private int customOpMode = 0; + /** * Starting {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, * {@link #isSessionConfigurationSupported} also checks for compatibility of session parameters @@ -581,6 +583,10 @@ public void run() { } } + public void setVendorStreamConfigMode(int fpsrange) { + customOpMode = fpsrange; + } + @Override public String getId() { return mCameraId; @@ -637,7 +643,11 @@ public boolean configureStreamsChecked(InputConfiguration inputConfig, if (!checkSurfaceSizesCompatible(outputs)) { return false; } - checkInputConfiguration(inputConfig); + try { + checkInputConfiguration(inputConfig); + } catch (IllegalArgumentException e) { + Log.w(TAG, "Check input configuration failed due to: " + e.getMessage()); + } boolean success = false; @@ -706,6 +716,7 @@ public boolean configureStreamsChecked(InputConfiguration inputConfig, mConfiguredOutputs.put(streamId, outConfig); } } + operatingMode = (operatingMode | (customOpMode << 16)); int offlineStreamIds[]; if (sessionParams != null) { diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index d7b6f116e4525..2570afaf1d6d4 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -605,36 +605,40 @@ private T getBase(CaptureRequest.Key key) { } private T getBase(Key key) { - int tag, nativeType; - byte[] values = null; - synchronized (this) { - if (key.hasTag()) { - tag = key.getTag(); - } else { - tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); - key.cacheTag(tag); - } - values = readValues(tag); - if (values == null) { - // If the key returns null, use the fallback key if exists. - // This is to support old key names for the newly published keys. - if (key.mFallbackName == null) { - return null; + try { + int tag, nativeType; + byte[] values = null; + synchronized (this) { + if (key.hasTag()) { + tag = key.getTag(); + } else { + tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); + key.cacheTag(tag); } - tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.mFallbackName); values = readValues(tag); if (values == null) { - return null; + // If the key returns null, use the fallback key if exists. + // This is to support old key names for the newly published keys. + if (key.mFallbackName == null) { + return null; + } + tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.mFallbackName); + values = readValues(tag); + if (values == null) { + return null; + } } - } - nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + } + // This block of code doesn't need to be synchronized since we aren't writing or reading + // from the metadata buffer for this instance of CameraMetadataNative. + Marshaler marshaler = getMarshalerForKey(key, nativeType); + ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); + return marshaler.unmarshal(buffer); + } catch (Exception e) { + return null; } - // This block of code doesn't need to be synchronized since we aren't writing or reading - // from the metadata buffer for this instance of CameraMetadataNative. - Marshaler marshaler = getMarshalerForKey(key, nativeType); - ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); - return marshaler.unmarshal(buffer); } // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden @@ -1993,30 +1997,34 @@ private void setBase(CaptureRequest.Key key, T value) { // we expect the metadata's properties such as vendor id etc to // stay the same and as a result the whole method should be synchronized for safety. private synchronized void setBase(Key key, T value) { - int tag, nativeType; - if (key.hasTag()) { - tag = key.getTag(); - } else { - tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); - key.cacheTag(tag); - } - if (value == null) { - // Erase the entry - writeValues(tag, /*src*/null); - return; - } // else update the entry to a new value + try { + int tag, nativeType; + if (key.hasTag()) { + tag = key.getTag(); + } else { + tag = nativeGetTagFromKeyLocal(mMetadataPtr, key.getName()); + key.cacheTag(tag); + } + if (value == null) { + // Erase the entry + writeValues(tag, /*src*/null); + return; + } // else update the entry to a new value - nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); - Marshaler marshaler = getMarshalerForKey(key, nativeType); - int size = marshaler.calculateMarshalSize(value); + nativeType = nativeGetTypeFromTagLocal(mMetadataPtr, tag); + Marshaler marshaler = getMarshalerForKey(key, nativeType); + int size = marshaler.calculateMarshalSize(value); - // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. - byte[] values = new byte[size]; + // TODO: Optimization. Cache the byte[] and reuse if the size is big enough. + byte[] values = new byte[size]; - ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); - marshaler.marshal(value, buffer); + ByteBuffer buffer = ByteBuffer.wrap(values).order(ByteOrder.nativeOrder()); + marshaler.marshal(value, buffer); - writeValues(tag, values); + writeValues(tag, values); + } catch (Exception e) { + // Do nothing + } } // Use Command pattern here to avoid lots of expensive if/equals checks in get for overridden diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java index 8bf94986a4905..0257ab979cb1f 100644 --- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java +++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java @@ -75,6 +75,20 @@ public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId, this.readoutTimestamp = readoutTimestamp; } + // Backwards-compatible constructor + public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId, + int precaptureTriggerId, long frameNumber, + int partialResultCount, int errorStreamId, + String errorPhysicalCameraId, long lastCompletedRegularFrameNumber, + long lastCompletedReprocessFrameNumber, + long lastCompletedZslFrameNumber) { + this(requestId, subsequenceId, afTriggerId, precaptureTriggerId, frameNumber, + partialResultCount, errorStreamId, errorPhysicalCameraId, + lastCompletedRegularFrameNumber, lastCompletedReprocessFrameNumber, + lastCompletedZslFrameNumber, + false /*hasReadOutTimestamp*/, 0 /*readoutTimestamp*/); + } + @Override public int describeContents() { return 0; diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java index 323459d553acf..e7a8dd41da202 100644 --- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java +++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java @@ -151,6 +151,136 @@ public StreamConfigurationMap( listHighResolution, /*enforceImplementationDefined*/ true); } + /** + * Create a new {@link StreamConfigurationMap}. + * + *

The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.

+ * + * @param configurations a non-{@code null} array of {@link StreamConfiguration} + * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration} + * @param depthMinFrameDurations a non-{@code null} array of depth + * {@link StreamConfigurationDuration} + * @param depthStallDurations a non-{@code null} array of depth + * {@link StreamConfigurationDuration} + * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth + * {@link StreamConfiguration} + * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth + * {@link StreamConfigurationDuration} + * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth + * {@link StreamConfigurationDuration} + * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration} + * @param heicMinFrameDurations a non-{@code null} array of heic + * {@link StreamConfigurationDuration} + * @param heicStallDurations a non-{@code null} array of heic + * {@link StreamConfigurationDuration} + * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if + * camera device does not support high speed video recording + * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE + * and thus needs a separate list of slow high-resolution output sizes + * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations + * were {@code null} or any subelements were {@code null} + * + * @hide + */ + public StreamConfigurationMap( + StreamConfiguration[] configurations, + StreamConfigurationDuration[] minFrameDurations, + StreamConfigurationDuration[] stallDurations, + StreamConfiguration[] depthConfigurations, + StreamConfigurationDuration[] depthMinFrameDurations, + StreamConfigurationDuration[] depthStallDurations, + StreamConfiguration[] dynamicDepthConfigurations, + StreamConfigurationDuration[] dynamicDepthMinFrameDurations, + StreamConfigurationDuration[] dynamicDepthStallDurations, + StreamConfiguration[] heicConfigurations, + StreamConfigurationDuration[] heicMinFrameDurations, + StreamConfigurationDuration[] heicStallDurations, + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, + ReprocessFormatsMap inputOutputFormatsMap, + boolean listHighResolution) { + this(configurations, minFrameDurations, stallDurations, + depthConfigurations, depthMinFrameDurations, depthStallDurations, + dynamicDepthConfigurations, dynamicDepthMinFrameDurations, + dynamicDepthStallDurations, + heicConfigurations, heicMinFrameDurations, heicStallDurations, + null /*jpegRConfigurations*/, null /*jpegRMinFrameDurations*/, null /*jpegRStallDurations*/, + null /*heicUltraHDRConfigurations*/, null /*heicUltraHDRMinFrameDurations*/, + null /*heicUltraHDRStallDurations*/, highSpeedVideoConfigurations, inputOutputFormatsMap, + listHighResolution, /*enforceImplementationDefined*/ true); + } + + /** + * Create a new {@link StreamConfigurationMap}. + * + *

The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.

+ * + * @param configurations a non-{@code null} array of {@link StreamConfiguration} + * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration} + * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration} + * @param depthMinFrameDurations a non-{@code null} array of depth + * {@link StreamConfigurationDuration} + * @param depthStallDurations a non-{@code null} array of depth + * {@link StreamConfigurationDuration} + * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth + * {@link StreamConfiguration} + * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth + * {@link StreamConfigurationDuration} + * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth + * {@link StreamConfigurationDuration} + * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration} + * @param heicMinFrameDurations a non-{@code null} array of heic + * {@link StreamConfigurationDuration} + * @param heicStallDurations a non-{@code null} array of heic + * {@link StreamConfigurationDuration} + * @param jpegRConfigurations a non-{@code null} array of Jpeg/R {@link StreamConfiguration} + * @param jpegRMinFrameDurations a non-{@code null} array of Jpeg/R + * {@link StreamConfigurationDuration} + * @param jpegRStallDurations a non-{@code null} array of Jpeg/R + * {@link StreamConfigurationDuration} + * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if + * camera device does not support high speed video recording + * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE + * and thus needs a separate list of slow high-resolution output sizes + * @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations + * were {@code null} or any subelements were {@code null} + * + * @hide + */ + public StreamConfigurationMap( + StreamConfiguration[] configurations, + StreamConfigurationDuration[] minFrameDurations, + StreamConfigurationDuration[] stallDurations, + StreamConfiguration[] depthConfigurations, + StreamConfigurationDuration[] depthMinFrameDurations, + StreamConfigurationDuration[] depthStallDurations, + StreamConfiguration[] dynamicDepthConfigurations, + StreamConfigurationDuration[] dynamicDepthMinFrameDurations, + StreamConfigurationDuration[] dynamicDepthStallDurations, + StreamConfiguration[] heicConfigurations, + StreamConfigurationDuration[] heicMinFrameDurations, + StreamConfigurationDuration[] heicStallDurations, + StreamConfiguration[] jpegRConfigurations, + StreamConfigurationDuration[] jpegRMinFrameDurations, + StreamConfigurationDuration[] jpegRStallDurations, + HighSpeedVideoConfiguration[] highSpeedVideoConfigurations, + ReprocessFormatsMap inputOutputFormatsMap, + boolean listHighResolution) { + this(configurations, minFrameDurations, stallDurations, + depthConfigurations, depthMinFrameDurations, depthStallDurations, + dynamicDepthConfigurations, dynamicDepthMinFrameDurations, + dynamicDepthStallDurations, + heicConfigurations, heicMinFrameDurations, heicStallDurations, + jpegRConfigurations, jpegRMinFrameDurations, jpegRStallDurations, + null /*heicUltraHDRConfigurations*/, null /*heicUltraHDRMinFrameDurations*/, + null /*heicUltraHDRStallDurations*/, highSpeedVideoConfigurations, inputOutputFormatsMap, + listHighResolution, /*enforceImplementationDefined*/ true); + } + /** * Create a new {@link StreamConfigurationMap}. * diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java index d341805b1588f..43592a9df94c2 100644 --- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java +++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java @@ -20,7 +20,10 @@ import android.annotation.TestApi; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.hardware.biometrics.Flags; +import android.os.BatteryManager; import android.os.Build; import android.os.SystemProperties; import android.provider.Settings; @@ -40,7 +43,10 @@ */ @TestApi public class AmbientDisplayConfiguration { - private static final String TAG = "AmbientDisplayConfig"; + private static final int DEFAULT_DOZE_PEEK_DURATION_SECONDS = 5; + private static final IntentFilter sIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + private static final long BATTERY_STATUS_CACHE_TTL_MS = 5000; // 5 seconds cache + private final Context mContext; private final boolean mAlwaysOnByDefault; private final boolean mPickupGestureEnabledByDefault; @@ -48,17 +54,24 @@ public class AmbientDisplayConfiguration { private final boolean mDozeEnabledByDefault; private final boolean mTapGestureEnabledByDefault; private final boolean mDoubleTapGestureEnabledByDefault; + + // Battery status cache + private boolean mCachedChargingStatus = false; + private long mBatteryStatusCacheTime = 0; /** Copied from android.provider.Settings.Secure since these keys are hidden. */ private static final String[] DOZE_SETTINGS = { Settings.Secure.DOZE_ENABLED, Settings.Secure.DOZE_ALWAYS_ON, + Settings.Secure.DOZE_PEEK, + Settings.Secure.DOZE_PEEK_DURATION, Settings.Secure.DOZE_PICK_UP_GESTURE, Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, - Settings.Secure.DOZE_TAP_SCREEN_GESTURE + Settings.Secure.DOZE_TAP_SCREEN_GESTURE, + Settings.Secure.DOZE_ON_CHARGE }; /** Non-user configurable doze settings */ @@ -93,10 +106,16 @@ public AmbientDisplayConfiguration(Context context) { public boolean enabled(int user) { return pulseOnNotificationEnabled(user) || pulseOnLongPressEnabled(user) - || alwaysOnEnabled(user) + || pulseOnCustomDozeEventEnabled(user) + || screenOffAodEnabled(user) + || edgeLightEnabled(user) + || isAmbientTickerEnabled(user) || wakeLockScreenGestureEnabled(user) || wakeDisplayGestureEnabled(user) || pickupGestureEnabled(user) + || tiltGestureEnabled(user) + || handwaveGestureEnabled(user) + || pocketGestureEnabled(user) || tapGestureEnabled(user) || doubleTapGestureEnabled(user) || quickPickupSensorEnabled(user) @@ -116,6 +135,17 @@ public boolean pulseOnNotificationAvailable() { && ambientDisplayAvailable(); } + /** {@hide} */ + private boolean pulseOnCustomDozeEventEnabled(int user) { + return (Settings.System.getIntForUser(mContext.getContentResolver(), "doze_trigger_doubletap", 0, user) != 0) + && pulseOnNotificationAvailable(); + } + + /** @hide */ + public boolean isAmbientTickerEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.PULSE_ON_NEW_TRACKS, user); + } + /** @hide */ public boolean pickupGestureEnabled(int user) { return boolSetting(Settings.Secure.DOZE_PICK_UP_GESTURE, user, @@ -123,11 +153,57 @@ public boolean pickupGestureEnabled(int user) { && dozePickupSensorAvailable(); } + /** @hide */ + public boolean pickupGestureAmbient(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_PICK_UP_GESTURE_AMBIENT, user) + && pickupGestureEnabled(user) && pulseOnNotificationEnabled(user); + } + + /** @hide */ + public boolean pickupGestureVibrate(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_PICK_UP_GESTURE_VIBRATE, user) + && pickupGestureEnabled(user); + } + /** @hide */ public boolean dozePickupSensorAvailable() { return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup); } + /** {@hide} */ + public boolean tiltGestureEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_TILT_GESTURE, user) + && dozeTiltSensorAvailable(); + } + + /** {@hide} */ + public boolean dozeTiltSensorAvailable() { + return mContext.getResources().getBoolean(R.bool.config_dozePulseTilt); + } + + /** {@hide} */ + public boolean handwaveGestureEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_HANDWAVE_GESTURE, user) + && dozeProximitySensorAvailable(); + } + + /** {@hide} */ + public boolean pocketGestureEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_POCKET_GESTURE, user) + && dozeProximitySensorAvailable(); + } + + /** {@hide} */ + public boolean dozeProximitySensorAvailable() { + return mContext.getResources().getBoolean(R.bool.config_dozePulseProximity); + } + + /** @hide */ + public boolean edgeLightEnabled(int user) { + return Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.EDGE_LIGHT_ENABLED, 0, user) != 0; + } + /** @hide */ public boolean tapGestureEnabled(int user) { return boolSetting(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user, @@ -135,6 +211,12 @@ public boolean tapGestureEnabled(int user) { && tapSensorAvailable(); } + /** @hide */ + public boolean tapGestureVibrate(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_TAP_GESTURE_VIBRATE, user) + && tapGestureEnabled(user); + } + /** @hide */ public boolean tapSensorAvailable() { for (String tapType : tapSensorTypeMapping()) { @@ -157,6 +239,18 @@ public boolean doubleTapSensorAvailable() { return !TextUtils.isEmpty(doubleTapSensorType()); } + /** @hide */ + public boolean tapGestureAmbient(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_TAP_GESTURE_AMBIENT, user) + && tapGestureEnabled(user) && pulseOnNotificationEnabled(user); + } + + /** @hide */ + public boolean doubleTapGestureVibrate(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE_VIBRATE, user) + && doubleTapGestureEnabled(user); + } + /** @hide */ public boolean quickPickupSensorEnabled(int user) { return boolSettingDefaultOn(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, user) @@ -167,11 +261,10 @@ && pickupGestureEnabled(user) /** @hide */ public boolean screenOffUdfpsEnabled(int user) { - return !TextUtils.isEmpty(udfpsLongPressSensorType()) - && ((mScreenOffUdfpsAvailable && Flags.screenOffUnlockUdfps()) - && mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_default_on) + if (!mScreenOffUdfpsAvailable) return false; + return mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_default_on) ? boolSettingDefaultOn(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user) - : boolSettingDefaultOff(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user)); + : boolSettingDefaultOff(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user); } /** @hide */ @@ -248,8 +341,108 @@ private boolean pulseOnLongPressAvailable() { */ @TestApi public boolean alwaysOnEnabled(int user) { - return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0) - && alwaysOnAvailable() && !accessibilityInversionEnabled(user); + return alwaysOnEnabledSetting(user) || alwaysOnChargingEnabled(user); + } + + /** + * Returns if any screen-off AOD experience should start for the current screen-off session. + * + *

This includes full AOD as well as a short-lived AOD peek. + * + * @hide + */ + public boolean screenOffAodEnabled(int user) { + return alwaysOnEnabled(user) || screenOffPeekEnabled(user); + } + + /** + * Returns if a short-lived screen-off AOD peek should be shown for the current user. + * + * @hide + */ + public boolean screenOffPeekEnabled(int user) { + return boolSettingDefaultOff(Settings.Secure.DOZE_PEEK, user) + && ambientDisplayAvailable() + && !alwaysOnEnabled(user) + && !accessibilityInversionEnabled(user); + } + + /** + * Returns the configured screen-off AOD peek duration in milliseconds. + * + * @hide + */ + public long getScreenOffPeekDurationMillis(int user) { + return getScreenOffPeekDurationSeconds(user) * 1000L; + } + + private int getScreenOffPeekDurationSeconds(int user) { + final int configuredDuration = Settings.Secure.getIntForUser( + mContext.getContentResolver(), + Settings.Secure.DOZE_PEEK_DURATION, + DEFAULT_DOZE_PEEK_DURATION_SECONDS, + user); + switch (configuredDuration) { + case 7: + case 10: + return configuredDuration; + case DEFAULT_DOZE_PEEK_DURATION_SECONDS: + default: + return DEFAULT_DOZE_PEEK_DURATION_SECONDS; + } + } + + /** @hide */ + public boolean alwaysOnEnabledSetting(int user) { + final boolean alwaysOnEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, + mAlwaysOnByDefault ? 1 : 0, user) == 1; + return alwaysOnEnabled && alwaysOnAvailable() && !accessibilityInversionEnabled(user); + } + + /** @hide */ + public boolean alwaysOnChargingEnabledSetting(int user) { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.DOZE_ON_CHARGE, 0, user) == 1; + } + + private boolean alwaysOnChargingEnabled(int user) { + if (alwaysOnChargingEnabledSetting(user)) { + long currentTime = System.currentTimeMillis(); + + // Use cached value if it's still valid + if (currentTime - mBatteryStatusCacheTime < BATTERY_STATUS_CACHE_TTL_MS) { + return mCachedChargingStatus; + } + + // Update cache with fresh battery status + final Intent intent = mContext.registerReceiver(null, sIntentFilter, Context.RECEIVER_NOT_EXPORTED); + if (intent != null) { + int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + + boolean chargingStatus; + + // Check if we have valid battery status and plugged values + if (status == -1 || plugged == -1) { + // Fallback to original logic if new values are invalid + chargingStatus = plugged != 0; + } else { + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + boolean isPlugged = plugged == BatteryManager.BATTERY_PLUGGED_AC || + plugged == BatteryManager.BATTERY_PLUGGED_USB || + plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; + chargingStatus = isPlugged && isCharging; + } + + // Update cache + mCachedChargingStatus = chargingStatus; + mBatteryStatusCacheTime = currentTime; + return chargingStatus; + } + } + return false; } /** diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 2174513c83e56..b149d03f351ad 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -24,17 +24,21 @@ import android.hardware.SensorManager; import android.hardware.input.HostUsiVersion; import android.os.Handler; +import android.os.IBinder; import android.os.PowerManager; import android.util.IntArray; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; +import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceControl.RefreshRateRange; import android.view.SurfaceControl.Transaction; import android.window.DisplayWindowPolicyController; import android.window.ScreenCaptureInternal; +import com.libremobileos.freeform.ILMOFreeformDisplayCallback; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -501,6 +505,17 @@ public abstract RefreshRateRange getRefreshRateForDisplayAndSensor( */ public abstract IntArray getDisplayIds(); + // LMOFreeform + public abstract void createFreeformLocked(String name, ILMOFreeformDisplayCallback callback, + int width, int height, int densityDpi, boolean secure, boolean ownContentOnly, + boolean shouldShowSystemDecorations, Surface surface, float refreshRate, + long presentationDeadlineNanos); + + public abstract void resizeFreeform(IBinder appToken, int width, int height, + int densityDpi); + + public abstract void releaseFreeform(IBinder appToken); + /** * Get group id for given display id */ diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index d470594a140ab..d8a467c451bc7 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -431,6 +431,10 @@ public void createSession(InputChannel channel, IInputMethodSessionCallback call @BinderThread @Override public void setSessionEnabled(IInputMethodSession session, boolean enabled) { + if (session == null) { + Log.w(TAG, "Incoming session is null"); + return; + } try { InputMethodSession ls = ((IInputMethodSessionWrapper) session).getInternalInputMethodSession(); diff --git a/core/java/android/location/Location.java b/core/java/android/location/Location.java index fd3e5a22e969e..fea7bc9315bd7 100644 --- a/core/java/android/location/Location.java +++ b/core/java/android/location/Location.java @@ -28,6 +28,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.Printer; import android.util.TimeUtils; @@ -805,6 +806,13 @@ public void setIsFromMockProvider(boolean isFromMockProvider) { * @see LocationManager#addTestProvider */ public boolean isMock() { + // Check if mock location override is enabled via Settings + boolean overrideMockDetection = SystemProperties.getBoolean( + "persist.sys.override_mock_location", false); + + if (overrideMockDetection) { + return false; + } return (mFieldsMask & HAS_MOCK_PROVIDER_MASK) != 0; } diff --git a/core/java/android/media/ImageReader.java b/core/java/android/media/ImageReader.java index ae80ad3e54a0e..6dfaefaf733df 100644 --- a/core/java/android/media/ImageReader.java +++ b/core/java/android/media/ImageReader.java @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import android.os.Trace; import android.view.Surface; @@ -909,7 +910,9 @@ public void detachImage(@Nullable Image image) { throw new IllegalStateException("Image was already detached from this ImageReader"); } - nativeDetachImage(image, mDetachThrowsIseOnly); + if (!SystemProperties.getBoolean("persist.sys.cam.skip_detach_image", false)) { + nativeDetachImage(image, mDetachThrowsIseOnly); + } si.clearSurfacePlanes(); si.mPlanes = null; si.setDetached(true); diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 570211ecc88d0..e5995d3005a58 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -103,6 +103,22 @@ public static RecurrenceRule buildRule(int cycleDay, ZoneId cycleTimezone) { } } + public static RecurrenceRule buildWeeklyRule(int cycleDay, ZoneId cycleTimezone) { + if (cycleDay != NetworkPolicy.CYCLE_NONE) { + return RecurrenceRule.buildRecurringWeekly(cycleDay, cycleTimezone); + } else { + return RecurrenceRule.buildNever(); + } + } + + public static RecurrenceRule buildDailyRule(int cycleDay, ZoneId cycleTimezone) { + if (cycleDay != NetworkPolicy.CYCLE_NONE) { + return RecurrenceRule.buildRecurringDaily(cycleDay, cycleTimezone); + } else { + return RecurrenceRule.buildNever(); + } + } + @Deprecated public NetworkPolicy(NetworkTemplate template, int cycleDay, String cycleTimezone, long warningBytes, long limitBytes, boolean metered) { diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index 65a4ebeec2546..b8c2b2a491fe2 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -529,6 +529,13 @@ private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean o } else { throw e; } + } catch (RuntimeException e) { + if (sShouldDefuse && (e.getCause() instanceof ClassNotFoundException)) { + Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e); + map.erase(); + } else { + throw e; + } } finally { mWeakParcelledData = null; if (ownsParcel) { diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java index cd64ab0bd77b8..a67b14ab546e2 100644 --- a/core/java/android/os/BatteryManager.java +++ b/core/java/android/os/BatteryManager.java @@ -281,6 +281,13 @@ public class BatteryManager { @SystemApi public static final String EXTRA_EVENT_TIMESTAMP = "android.os.extra.EVENT_TIMESTAMP"; + /** + * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: + * boolean value to detect fast charging + * {@hide} + */ + public static final String EXTRA_OEM_CHARGER = "oem_charger"; + // values for "status" field in the ACTION_BATTERY_CHANGED Intent public static final int BATTERY_STATUS_UNKNOWN = Constants.BATTERY_STATUS_UNKNOWN; public static final int BATTERY_STATUS_CHARGING = Constants.BATTERY_STATUS_CHARGING; diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java index 9e52075938baf..9ed6228fb2183 100644 --- a/core/java/android/os/FileObserver.java +++ b/core/java/android/os/FileObserver.java @@ -161,6 +161,7 @@ public void onEvent(int wfd, @NotifyEventType int mask, String path) { observer = (FileObserver) weak.get(); if (observer == null) { mRealObservers.remove(wfd); + return; } } } diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 10a2941abd7ea..8f276d00b97b6 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -597,9 +597,15 @@ public static String userActivityEventToString(@UserActivityEvent int userActivi public static final int GO_TO_SLEEP_REASON_UNKNOWN = 14; /** + * Go to sleep reason code: Going to sleep due to a touch tap or double tap. * @hide */ - public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_UNKNOWN; + public static final int GO_TO_SLEEP_REASON_TOUCH = 15; + + /** + * @hide + */ + public static final int GO_TO_SLEEP_REASON_MAX = GO_TO_SLEEP_REASON_TOUCH; /** * @hide @@ -620,6 +626,7 @@ public static String sleepReasonToString(@GoToSleepReason int sleepReason) { case GO_TO_SLEEP_REASON_QUIESCENT: return "quiescent"; case GO_TO_SLEEP_REASON_SLEEP_BUTTON: return "sleep_button"; case GO_TO_SLEEP_REASON_TIMEOUT: return "timeout"; + case GO_TO_SLEEP_REASON_TOUCH: return "touch"; case GO_TO_SLEEP_REASON_UNKNOWN: return "unknown"; default: return Integer.toString(sleepReason); } @@ -733,6 +740,7 @@ public static String sleepReasonToString(@GoToSleepReason int sleepReason) { GO_TO_SLEEP_REASON_QUIESCENT, GO_TO_SLEEP_REASON_SLEEP_BUTTON, GO_TO_SLEEP_REASON_TIMEOUT, + GO_TO_SLEEP_REASON_TOUCH, GO_TO_SLEEP_REASON_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index a1b0d9586a640..612a29ad33b68 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -1526,9 +1526,9 @@ public static void initThreadDefaults(ApplicationInfo ai) { builder.penaltyDeathOnNetwork(); } - if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { + if (Build.IS_USER || Build.IS_USERDEBUG || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { // Detect nothing extra - } else if (Build.IS_USERDEBUG || Build.IS_ENG) { + } else if (Build.IS_ENG) { // Detect everything in bundled apps if (isBundledSystemApp(ai)) { builder.detectAll(); @@ -1559,18 +1559,12 @@ public static void initVmDefaults(ApplicationInfo ai) { if (targetSdkVersion >= Build.VERSION_CODES.N) { builder.detectFileUriExposure(); builder.penaltyDeathOnFileUriExposure(); + builder.detectActivityLeaks(); + builder.detectLeakedRegistrationObjects(); } - if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { + if (Build.IS_USER || Build.IS_USERDEBUG || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) { // Detect nothing extra - } else if (Build.IS_USERDEBUG) { - // Detect everything in bundled apps (except activity leaks, which - // are expensive to track) - if (isBundledSystemApp(ai)) { - builder.detectAll(); - builder.permitActivityLeaks(); - builder.penaltyDropBox(); - } } else if (Build.IS_ENG) { // Detect everything in bundled apps if (isBundledSystemApp(ai)) { @@ -2226,12 +2220,18 @@ public static void setVmPolicy(final VmPolicy policy) { } } + private static volatile BackgroundActivityLaunchCallback sBackgroundActivityLaunchCallback; + private static void registerBackgroundActivityLaunchCallback() { + if (sBackgroundActivityLaunchCallback != null) { + return; + } + sBackgroundActivityLaunchCallback = new BackgroundActivityLaunchCallback(); try { IActivityTaskManager service = ActivityTaskManager.getService(); if (service != null) { service.registerBackgroundActivityStartCallback( - new BackgroundActivityLaunchCallback()); + sBackgroundActivityLaunchCallback); } } catch (DeadObjectException e) { // ignore @@ -2663,7 +2663,9 @@ private static void clampViolationTimeMap(final @NonNull SparseLongArray violati /** @hide */ public static void onVmPolicyViolation(Violation originStack) { - onVmPolicyViolation(originStack, false); + boolean forceDeath = originStack instanceof IntentReceiverLeakedViolation + || originStack instanceof ServiceConnectionLeakedViolation; + onVmPolicyViolation(originStack, forceDeath); } /** @hide */ @@ -2922,7 +2924,7 @@ protected IWindowManager create() { */ @UnsupportedAppUsage public static Span enterCriticalSpan(String name) { - if (Build.IS_USER) { + if (Build.IS_USER || Build.IS_USERDEBUG) { return NO_OP_SPAN; } if (name == null || name.isEmpty()) { diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java index 1c4f0fe46d831..b9345c8deb6a0 100644 --- a/core/java/android/os/Trace.java +++ b/core/java/android/os/Trace.java @@ -180,6 +180,9 @@ private Trace() { @UnsupportedAppUsage @SystemApi(client = MODULE_LIBRARIES) public static boolean isTagEnabled(long traceTag) { + if (!Build.IS_ENG) { + return false; + } return nativeIsTagEnabled(traceTag); } diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java index e7957a785693a..b3f626f7ff4af 100644 --- a/core/java/android/os/VibratorInfo.java +++ b/core/java/android/os/VibratorInfo.java @@ -690,6 +690,15 @@ public FrequencyProfile(float resonantFrequencyHz, float[] frequenciesHz, mResonantFrequencyHz = resonantFrequencyHz; + if (frequenciesHz == null && outputAccelerationsGs == null) { + mFrequenciesHz = null; + mOutputAccelerationsGs = null; + mMinFrequencyHz = Float.NaN; + mMaxFrequencyHz = Float.NaN; + mMaxOutputAccelerationGs = Float.NaN; + return; + } + boolean isValid = (frequenciesHz != null && outputAccelerationsGs != null) && (frequenciesHz.length == outputAccelerationsGs.length) && (frequenciesHz.length > 0); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index e45a740b8ab9b..47552d6e40fc2 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -174,6 +174,7 @@ public final class PermissionManager { "permission grant or revoke changed gids"; private static final String SYSTEM_PKG = "android"; + private static final String FACEAUTH_PKG = "co.aospa.sense"; /** * Refuse to install package if groups of permissions are bad @@ -1355,6 +1356,7 @@ public static Set getIndicatorExemptedPackages(@NonNull Context context) updateIndicatorExemptedPackages(context); ArraySet pkgNames = new ArraySet<>(); pkgNames.add(SYSTEM_PKG); + pkgNames.add(FACEAUTH_PKG); for (int i = 0; i < INDICATOR_EXEMPTED_PACKAGES.length; i++) { String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i]; if (exemptedPackage != null) { diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index ef434cd5e7879..a09ba797bdf47 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -59,6 +59,7 @@ import android.os.UserManager; import android.permission.flags.Flags; import android.provider.DeviceConfig; +import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.ArraySet; @@ -84,11 +85,6 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis private static final String LOG_TAG = PermissionUsageHelper.class.getName(); - /** - * Whether to show the mic and camera icons. - */ - private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; - /** * How long after an access to show it as "recent" */ @@ -108,10 +104,20 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // LINT.ThenChange(/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt, /packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java) private static final long DEFAULT_RECENT_TIME_MS = 15000L; - private static boolean shouldShowIndicators() { - return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_CAMERA_MIC_ICONS_ENABLED, true) - || android.location.flags.Flags.locationIndicatorsEnabled(); + private boolean shouldShowIndicators() { + return shouldShowCameraIndicator() || shouldShowLocationIndicator(); + } + + private boolean shouldShowCameraIndicator() { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ENABLE_CAMERA_PRIVACY_INDICATOR, 1, + UserHandle.USER_CURRENT) == 1; + } + + private boolean shouldShowLocationIndicator() { + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ENABLE_LOCATION_PRIVACY_INDICATOR, 1, + UserHandle.USER_CURRENT) == 1; } private static long getRecentThreshold(Long now) { @@ -297,11 +303,15 @@ private void addLinkToChainIfNotPresentLocked(String op, String packageName, int return usages; } - List ops = new ArrayList<>(CAMERA_OPS); - if (includeMicrophoneUsage) { - ops.addAll(MIC_OPS); + List ops = new ArrayList<>(); + if (shouldShowCameraIndicator()) { + ops.addAll(CAMERA_OPS); + if (includeMicrophoneUsage) { + ops.addAll(MIC_OPS); + } } - if (android.location.flags.Flags.locationIndicatorsEnabled()) { + + if (shouldShowLocationIndicator()) { ops.addAll(LOCATION_OPS); } @@ -603,7 +613,7 @@ private Map> getOpUsagesByDevice(List opNames, Str String permGroupName = getGroupForOp(op); boolean isLocationOp = - android.location.flags.Flags.locationIndicatorsEnabled() + shouldShowLocationIndicator() && LOCATION.equals(permGroupName); long currentRunningThreshold = runningThreshold diff --git a/core/java/android/pocket/IPocketCallback.aidl b/core/java/android/pocket/IPocketCallback.aidl new file mode 100644 index 0000000000000..53e5412f89beb --- /dev/null +++ b/core/java/android/pocket/IPocketCallback.aidl @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2016 The ParanoidAndroid 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 android.pocket; + +/** @hide */ +interface IPocketCallback { + + // notify when pocket state changes. + void onStateChanged(boolean isDeviceInPocket, int reason); + +} \ No newline at end of file diff --git a/core/java/android/pocket/IPocketService.aidl b/core/java/android/pocket/IPocketService.aidl new file mode 100644 index 0000000000000..783465774207b --- /dev/null +++ b/core/java/android/pocket/IPocketService.aidl @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2016 The ParanoidAndroid 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 android.pocket; + +import android.pocket.IPocketCallback; + +/** @hide */ +interface IPocketService { + + // add callback to get notified about pocket state. + void addCallback(IPocketCallback callback); + + // remove callback and stop getting notified about pocket state. + void removeCallback(IPocketCallback callback); + + // notify pocket service about intercative state changed. + // @see com.android.policy.PhoneWindowManager + void onInteractiveChanged(boolean interactive); + + // external processes can request changing listening state. + void setListeningExternal(boolean listen); + + // check if device is in pocket. + boolean isDeviceInPocket(); + + // Custom methods + void setPocketLockVisible(boolean visible); + boolean isPocketLockVisible(); + +} \ No newline at end of file diff --git a/core/java/android/pocket/PocketConstants.java b/core/java/android/pocket/PocketConstants.java new file mode 100644 index 0000000000000..70aa74a7f2a69 --- /dev/null +++ b/core/java/android/pocket/PocketConstants.java @@ -0,0 +1,19 @@ +package android.pocket; + +/** + * This class contains global pocket setup constants. + * @author Carlo Savignano + * @hide + */ + +public class PocketConstants { + + public static final boolean DEBUG = false; + public static final boolean DEBUG_SPEW = false; + + /** + * Whether to use proximity sensor to evaluate pocket state. + */ + public static final boolean ENABLE_PROXIMITY_JUDGE = true; + +} diff --git a/core/java/android/pocket/PocketManager.java b/core/java/android/pocket/PocketManager.java new file mode 100644 index 0000000000000..cad5635d17ad6 --- /dev/null +++ b/core/java/android/pocket/PocketManager.java @@ -0,0 +1,237 @@ +/** + * Copyright (C) 2016 The ParanoidAndroid 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 android.pocket; + +import android.content.Context; +import android.os.Handler; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.telecom.TelecomManager; +import android.text.format.DateUtils; +import android.util.Log; +import android.util.Slog; + +/** + * A class that coordinates listening for pocket state. + *

+ * Use {@link android.content.Context#getSystemService(java.lang.String)} + * with argument {@link android.content.Context#POCKET_SERVICE} to get + * an instance of this class. + * + * Usage: import and create a final {@link IPocketCallback.Stub()} and implement your logic in + * {@link IPocketCallback#onStateChanged(boolean, int)}. Then add your callback to the pocket manager + * + * // define a final callback + * private final IPocketCallback mCallback = new IPocketCallback.Stub() { + * + * @Override + * public void onStateChanged(boolean isDeviceInPocket, int reason) { + * // Your method to handle logic outside of this callback, ideally with a handler + * // posting on UI Thread for view hierarchy operations or with its own background thread. + * handlePocketStateChanged(isDeviceInPocket, reason); + * } + * + * } + * + * // add callback to pocket manager + * private void addCallback() { + * PocketManager manager = (PocketManager) context.getSystemService(Context.POCKET_SERVICE); + * manager.addCallback(mCallback); + * } + * + * @author Carlo Savignano + * @hide + */ +public class PocketManager { + + private static final String TAG = PocketManager.class.getSimpleName(); + static final boolean DEBUG = false; + + /** + * Whether {@link IPocketCallback#onStateChanged(boolean, int)} + * was fired because of the sensor. + * @see PocketService#handleDispatchCallbacks() + */ + public static final int REASON_SENSOR = 0; + + /** + * Whether {@link IPocketCallback#onStateChanged(boolean, int)} + * was fired because of an error while accessing service. + * @see #addCallback(IPocketCallback) + * @see #removeCallback(IPocketCallback) + */ + public static final int REASON_ERROR = 1; + + /** + * Whether {@link IPocketCallback#onStateChanged(boolean, int)} + * was fired because of a needed reset. + * @see PocketService#binderDied() + */ + public static final int REASON_RESET = 2; + + private final Context mContext; + private final IPocketService mService; + private final PowerManager mPowerManager; + private final TelecomManager mTelecomManager; + private final Handler mHandler; + private boolean mPocketViewTimerActive; + + public PocketManager(Context context, IPocketService service) { + mContext = context; + mService = service; + if (mService == null) { + Slog.v(TAG, "PocketService was null"); + } + mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); + mHandler = new Handler(); + } + + /** + * Add pocket state callback. + * @see PocketService#handleRemoveCallback(IPocketCallback) + */ + public void addCallback(final IPocketCallback callback) { + if (mService != null) try { + mService.addCallback(callback); + } catch (RemoteException e1) { + Log.w(TAG, "Remote exception in addCallback: ", e1); + if (callback != null){ + try { + callback.onStateChanged(false, REASON_ERROR); + } catch (RemoteException e2) { + Log.w(TAG, "Remote exception in callback.onPocketStateChanged: ", e2); + } + } + } + } + + /** + * Remove pocket state callback. + * @see PocketService#handleAddCallback(IPocketCallback) + */ + public void removeCallback(final IPocketCallback callback) { + if (mService != null) try { + mService.removeCallback(callback); + } catch (RemoteException e1) { + Log.w(TAG, "Remote exception in removeCallback: ", e1); + if (callback != null){ + try { + callback.onStateChanged(false, REASON_ERROR); + } catch (RemoteException e2) { + Log.w(TAG, "Remote exception in callback.onPocketStateChanged: ", e2); + } + } + } + } + + /** + * Notify service about device interactive state changed. + * {@link PhoneWindowManager#startedWakingUp()} + * {@link PhoneWindowManager#startedGoingToSleep(int)} + */ + public void onInteractiveChanged(boolean interactive) { + boolean isPocketViewShowing = (interactive && isDeviceInPocket()); + synchronized (mPocketLockTimeout) { + if (mPocketViewTimerActive != isPocketViewShowing) { + if (isPocketViewShowing) { + if (DEBUG) Log.v(TAG, "Setting pocket timer"); + mHandler.removeCallbacks(mPocketLockTimeout); // remove any pending requests + mHandler.postDelayed(mPocketLockTimeout, 3 * DateUtils.SECOND_IN_MILLIS); + mPocketViewTimerActive = true; + } else { + if (DEBUG) Log.v(TAG, "Clearing pocket timer"); + mHandler.removeCallbacks(mPocketLockTimeout); + mPocketViewTimerActive = false; + } + } + } + if (mService != null) try { + mService.onInteractiveChanged(interactive); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception in addCallback: ", e); + } + } + + /** + * Request listening state change by, but not limited to, external process. + * @see PocketService#handleSetListeningExternal(boolean) + */ + public void setListeningExternal(boolean listen) { + if (mService != null) try { + mService.setListeningExternal(listen); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception in setListeningExternal: ", e); + } + // Clear timeout when user hides pocket lock with long press power. + if (mPocketViewTimerActive && !listen) { + if (DEBUG) Log.v(TAG, "Clearing pocket timer due to override"); + mHandler.removeCallbacks(mPocketLockTimeout); + mPocketViewTimerActive = false; + } + } + + /** + * Return whether device is in pocket. + * @see PocketService#isDeviceInPocket() + * @return + */ + public boolean isDeviceInPocket() { + if (mService != null) try { + return mService.isDeviceInPocket(); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception in isDeviceInPocket: ", e); + } + return false; + } + + class PocketLockTimeout implements Runnable { + @Override + public void run() { + if (!mTelecomManager.isInCall()) + mPowerManager.goToSleep(SystemClock.uptimeMillis()); + mPocketViewTimerActive = false; + } + } + + /** Custom methods **/ + + public void setPocketLockVisible(boolean visible) { + if (!visible){ + if (DEBUG) Log.v(TAG, "Clearing pocket timer"); + mHandler.removeCallbacks(mPocketLockTimeout); + mPocketViewTimerActive = false; + } + if (mService != null) try { + mService.setPocketLockVisible(visible); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception in setPocketLockVisible: ", e); + } + } + + public boolean isPocketLockVisible() { + if (mService != null) try { + return mService.isPocketLockVisible(); + } catch (RemoteException e) { + Log.w(TAG, "Remote exception in isPocketLockVisible: ", e); + } + return false; + } + + private PocketLockTimeout mPocketLockTimeout = new PocketLockTimeout(); + +} diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java index e15244ac0df03..3576ec87a7e7f 100644 --- a/core/java/android/preference/RingtonePreference.java +++ b/core/java/android/preference/RingtonePreference.java @@ -33,6 +33,7 @@ *

* If the user chooses the "Default" item, the saved string will be one of * {@link System#DEFAULT_RINGTONE_URI}, + * {@link System#DEFAULT_RINGTONE2_URI}, * {@link System#DEFAULT_NOTIFICATION_URI}, or * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent" * item, the saved string will be an empty string. diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 687a448d780ae..648433afcfaf7 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -3298,6 +3298,9 @@ public boolean equals(Object obj) { Bundle response = nullSafeCall(resolver, ContactsContract.AUTHORITY_URI, QUERY_DEFAULT_ACCOUNT_FOR_NEW_CONTACTS_METHOD, null, null); + if (response == null) { + return DefaultAccountAndState.ofNotSet(); + } int defaultAccountState = response.getInt(KEY_DEFAULT_ACCOUNT_STATE, -1); if (DefaultAccountAndState.isCloudOrSimAccount(defaultAccountState)) { String accountName = response.getString(Settings.ACCOUNT_NAME); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 36e2193cec11c..c107cb9f91517 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -126,6 +126,8 @@ import java.util.concurrent.Executor; import java.util.function.Consumer; +import com.android.internal.util.matrixx.DeviceConfigUtils; + /** * The Settings provider contains global system-level device preferences. */ @@ -3046,6 +3048,21 @@ public final class Settings { public static final String ACTION_APP_PERMISSIONS_SETTINGS = "android.settings.APP_PERMISSIONS_SETTINGS"; + /** + * Activity Action: Show screen that lets user configure private DNS + *

+ * In some cases, a matching Activity may not exist, so ensure you safeguard against this. + *

+ * Input: Nothing + *

+ * Output: Nothing + * + * @hide + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_PRIVATE_DNS_SETTING = + "com.android.settings.PRIVATE_DNS_SETTINGS"; + // End of Intent actions for Settings /** @@ -5830,6 +5847,17 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean @Readable public static final String RINGTONE = "ringtone"; + /** + * Persistent store for the system-wide default ringtone for Slot2 URI. + * + * @see #RINGTONE + * @see #DEFAULT_RINGTONE2_URI + * + */ + /** @hide */ + @Readable + public static final String RINGTONE2 = "ringtone2"; + /** * A {@link Uri} that will point to the current default ringtone at any * given time. @@ -5840,11 +5868,26 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean */ public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE); + /** + * A {@link Uri} that will point to the current default ringtone for Slot2 + * at any given time. + * + * @see #DEFAULT_RINGTONE_URI + * + */ + /** @hide */ + public static final Uri DEFAULT_RINGTONE2_URI = getUriFor(RINGTONE2); + /** @hide */ public static final String RINGTONE_CACHE = "ringtone_cache"; /** @hide */ public static final Uri RINGTONE_CACHE_URI = getUriFor(RINGTONE_CACHE); + /** @hide */ + public static final String RINGTONE2_CACHE = "ringtone2_cache"; + /** @hide */ + public static final Uri RINGTONE2_CACHE_URI = getUriFor(RINGTONE2_CACHE); + /** * Persistent store for the system-wide default notification sound. * @@ -6553,6 +6596,14 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean public static final String MOUSE_POINTER_ACCELERATION_ENABLED = "mouse_pointer_acceleration_enabled"; + /** + * Whether to enable smart 5G mode. + * When enabled, 5G is disabled when battery saver is on, mobile data is inactive + * (e.g. on WiFi), or the subscription is not the default data SIM. + * @hide + */ + public static final String SMART_5G = "smart_5g"; + /** * Mouse scrolling speed setting. * @@ -6726,6 +6777,13 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean @Readable public static final String VOLUME_KEY_CURSOR_CONTROL = "volume_key_cursor_control"; + /** + * Whether long press on navbar gesture is enabled + * @hide + */ + @Readable + public static final String NAVBAR_LONG_PRESS_GESTURE = "navbar_long_press_gesture"; + /** * IMPORTANT: If you add a new public settings you also have to add it to * PUBLIC_SETTINGS below. If the new setting is hidden you have to add @@ -6734,564 +6792,1539 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean */ /** - * Keys we no longer back up under the current schema, but want to continue to - * process when restoring historical backup datasets. - * - * All settings in {@link LEGACY_RESTORE_SETTINGS} array *must* have a non-null validator, - * otherwise they won't be restored. - * + * Whether the phone vibrates on call connect * @hide */ - public static final String[] LEGACY_RESTORE_SETTINGS = { - }; + @Readable + public static final String VIBRATE_ON_CONNECT = "vibrate_on_connect"; /** - * These are all public system settings - * + * Whether the phone vibrates on call waiting * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final Set PUBLIC_SETTINGS = new ArraySet<>(); - static { - PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR); - PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP); - PUBLIC_SETTINGS.add(WIFI_STATIC_IP); - PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY); - PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK); - PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1); - PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2); - PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY); - PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT); - PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED); - PUBLIC_SETTINGS.add(FONT_SCALE); - PUBLIC_SETTINGS.add(SYSTEM_LOCALES); - PUBLIC_SETTINGS.add(DIM_SCREEN); - PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT); - PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS); - PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE); - PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED); - PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED); - PUBLIC_SETTINGS.add(VIBRATE_ON); - PUBLIC_SETTINGS.add(VOLUME_RING); - PUBLIC_SETTINGS.add(VOLUME_SYSTEM); - PUBLIC_SETTINGS.add(VOLUME_VOICE); - PUBLIC_SETTINGS.add(VOLUME_MUSIC); - PUBLIC_SETTINGS.add(VOLUME_ALARM); - PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION); - PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO); - PUBLIC_SETTINGS.add(VOLUME_ASSISTANT); - PUBLIC_SETTINGS.add(RINGTONE); - PUBLIC_SETTINGS.add(NOTIFICATION_SOUND); - PUBLIC_SETTINGS.add(ALARM_ALERT); - PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE); - PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS); - PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE); - PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD); - PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS); - PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY); - PUBLIC_SETTINGS.add(TIME_12_24); - PUBLIC_SETTINGS.add(DATE_FORMAT); - PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN); - PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION); - PUBLIC_SETTINGS.add(USER_ROTATION); - PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING); - PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED); - PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED); - PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS); - PUBLIC_SETTINGS.add(VIBRATE_WHEN_RINGING); - PUBLIC_SETTINGS.add(APPLY_RAMPING_RINGER); - } + @Readable + public static final String VIBRATE_ON_CALLWAITING = "vibrate_on_callwaiting"; /** - * These are all hidden system settings. - * + * Whether the phone vibrates on disconnect * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final Set PRIVATE_SETTINGS = new ArraySet<>(); - static { - PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP); - PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR); - PRIVATE_SETTINGS.add(ADVANCED_SETTINGS); - PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_DISABLE); - PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_ENABLE); - PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED); - PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE); - PRIVATE_SETTINGS.add(WEAR_TTS_PREWARM_ENABLED); - PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ); - PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES); - PRIVATE_SETTINGS.add(VOLUME_MASTER); - PRIVATE_SETTINGS.add(MASTER_MONO); - PRIVATE_SETTINGS.add(MASTER_BALANCE); - PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME); - PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT); - PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER); - PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY); - PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING); - PRIVATE_SETTINGS.add(HEARING_AID_COMPATIBILITY); - PRIVATE_SETTINGS.add(TTY_MODE); - PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE); - PRIVATE_SETTINGS.add(POINTER_LOCATION); - PRIVATE_SETTINGS.add(SHOW_TOUCHES); - PRIVATE_SETTINGS.add(SHOW_KEY_PRESSES); - PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG); - PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED); - PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED); - PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED); - PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED); - PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND); - PRIVATE_SETTINGS.add(DESK_DOCK_SOUND); - PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND); - PRIVATE_SETTINGS.add(CAR_DOCK_SOUND); - PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND); - PRIVATE_SETTINGS.add(LOCK_SOUND); - PRIVATE_SETTINGS.add(UNLOCK_SOUND); - PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS); - PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS); - PRIVATE_SETTINGS.add(SIP_ALWAYS); - PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY); - PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME); - PRIVATE_SETTINGS.add(POINTER_SPEED); - PRIVATE_SETTINGS.add(POINTER_FILL_STYLE); - PRIVATE_SETTINGS.add(POINTER_STROKE_STYLE); - PRIVATE_SETTINGS.add(POINTER_SCALE); - PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED); - PRIVATE_SETTINGS.add(EGG_MODE); - PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT); - PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE); - PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE_VENDOR_HINT); - PRIVATE_SETTINGS.add(LOCALE_PREFERENCES); - PRIVATE_SETTINGS.add(TOUCHPAD_POINTER_SPEED); - PRIVATE_SETTINGS.add(TOUCHPAD_NATURAL_SCROLLING); - PRIVATE_SETTINGS.add(TOUCHPAD_TAP_TO_CLICK); - PRIVATE_SETTINGS.add(TOUCHPAD_TAP_DRAGGING); - PRIVATE_SETTINGS.add(TOUCHPAD_RIGHT_CLICK_ZONE); - PRIVATE_SETTINGS.add(TOUCHPAD_SYSTEM_GESTURES); - PRIVATE_SETTINGS.add(TOUCHPAD_ACCELERATION_ENABLED); - PRIVATE_SETTINGS.add(TOUCHPAD_ENABLED); - PRIVATE_SETTINGS.add(CAMERA_FLASH_NOTIFICATION); - PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION); - PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION_COLOR); - PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE); - PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING); - PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON); - PRIVATE_SETTINGS.add(MOUSE_POINTER_ACCELERATION_ENABLED); - PRIVATE_SETTINGS.add(PREFERRED_REGION); - PRIVATE_SETTINGS.add(MOUSE_SCROLLING_ACCELERATION); - PRIVATE_SETTINGS.add(MOUSE_SCROLLING_SPEED); - } + @Readable + public static final String VIBRATE_ON_DISCONNECT = "vibrate_on_disconnect"; /** - * These entries are considered common between the personal and the managed profile, - * since the managed profile doesn't get to change them. + * Whether to blink flashlight for incoming calls + * 0 = Disabled (Default) + * 1 = Blink flashlight only in Ringer mode + * 2 = Blink flashlight only when ringer is not audible + * 3 = Blink flahslight only when entirely silent + * 4 = Blink flashlight always regardless of ringer mode + * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static final Set CLONE_TO_MANAGED_PROFILE = new ArraySet<>(); - static { - CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT); - CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED); - CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED); - CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD); - CLONE_TO_MANAGED_PROFILE.add(TIME_12_24); - } - - /** @hide */ - public static void getCloneToManagedProfileSettings(Set outKeySet) { - outKeySet.addAll(CLONE_TO_MANAGED_PROFILE); - } + @Readable + public static final String FLASHLIGHT_ON_CALL = "flashlight_on_call"; /** - * These entries should be cloned from this profile's parent only if the dependency's - * value is true ("1") - * - * Note: the dependencies must be Secure settings - * + * Whether flashlight_on_call ignores DND (Zen Mode) * @hide */ - public static final Map CLONE_FROM_PARENT_ON_VALUE = new ArrayMap<>(); - static { - CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE, Secure.SYNC_PARENT_SOUNDS); - CLONE_FROM_PARENT_ON_VALUE.put(NOTIFICATION_SOUND, Secure.SYNC_PARENT_SOUNDS); - CLONE_FROM_PARENT_ON_VALUE.put(ALARM_ALERT, Secure.SYNC_PARENT_SOUNDS); - } - - /** @hide */ - public static void getCloneFromParentOnValueSettings(Map outMap) { - outMap.putAll(CLONE_FROM_PARENT_ON_VALUE); - } + @Readable + public static final String FLASHLIGHT_ON_CALL_IGNORE_DND = "flashlight_on_call_ignore_dnd"; /** - * System settings which can be accessed by instant apps. + * Rate in Hz in which to blink flashlight_on_call * @hide */ - public static final Set INSTANT_APP_SETTINGS = new ArraySet<>(); - static { - INSTANT_APP_SETTINGS.add(TEXT_AUTO_REPLACE); - INSTANT_APP_SETTINGS.add(TEXT_AUTO_CAPS); - INSTANT_APP_SETTINGS.add(TEXT_AUTO_PUNCTUATE); - INSTANT_APP_SETTINGS.add(TEXT_SHOW_PASSWORD); - INSTANT_APP_SETTINGS.add(DATE_FORMAT); - INSTANT_APP_SETTINGS.add(FONT_SCALE); - INSTANT_APP_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED); - INSTANT_APP_SETTINGS.add(TIME_12_24); - INSTANT_APP_SETTINGS.add(SOUND_EFFECTS_ENABLED); - INSTANT_APP_SETTINGS.add(ACCELEROMETER_ROTATION); - } + @Readable + public static final String FLASHLIGHT_ON_CALL_RATE = "flashlight_on_call_rate"; /** - * When to use Wi-Fi calling - * - * @see android.telephony.TelephonyManager.WifiCallingChoices + * Which Vibration Pattern to use + * 0: dzzz-dzzz + * 1: dzzz-da + * 2: mm-mm-mm + * 3: da-da-dzzz + * 4: da-dzzz-da + * 5: custom * @hide */ @Readable - public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls"; + public static final String RINGTONE_VIBRATION_PATTERN = "ringtone_vibration_pattern"; - /** Controls whether bluetooth is on or off on wearable devices. - * - *

The valid values for this key are: 0 (disabled) or 1 (enabled). - * + /** + * Custom vibration pattern + * format: ms,ms,ms each a range from 0 to 1000 ms * @hide */ - public static final String CLOCKWORK_BLUETOOTH_SETTINGS_PREF = "cw_bt_settings_pref"; + @Readable + public static final String CUSTOM_RINGTONE_VIBRATION_PATTERN = "custom_ringtone_vibration_pattern"; /** - * Controls whether the unread notification dot indicator is shown on wearable devices. - * - *

The valid values for this key are: 0 (disabled) or 1 (enabled). - * + * Whether to show seconds next to clock in status bar + * 0 - hide (default) + * 1 - show * @hide */ - public static final String UNREAD_NOTIFICATION_DOT_INDICATOR = - "unread_notification_dot_indicator"; + public static final String STATUS_BAR_CLOCK_SECONDS = "status_bar_clock_seconds"; /** - * Controls whether auto-launching media controls is enabled on wearable devices. - * - *

The valid values for this key are: 0 (disabled) or 1 (enabled). - * + * Shows custom date before clock time + * 0 - No Date + * 1 - Small Date + * 2 - Normal Date * @hide */ - public static final String AUTO_LAUNCH_MEDIA_CONTROLS = "auto_launch_media_controls"; - - // Settings moved to Settings.Secure + public static final String STATUS_BAR_CLOCK_DATE_DISPLAY = "status_bar_clock_date_display"; /** - * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} - * instead + * Sets the date string style + * 0 - Regular style + * 1 - Lowercase + * 2 - Uppercase + * @hide */ - @Deprecated - public static final String ADB_ENABLED = Global.ADB_ENABLED; + public static final String STATUS_BAR_CLOCK_DATE_STYLE = "status_bar_clock_date_style"; /** - * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead + * Position of date + * 0 - Left of clock + * 1 - Right of clock + * @hide */ - @Deprecated - public static final String ANDROID_ID = Secure.ANDROID_ID; + public static final String STATUS_BAR_CLOCK_DATE_POSITION = "status_bar_clock_date_position"; /** - * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead + * Stores the java DateFormat string for the date + * @hide */ - @Deprecated - public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; + public static final String STATUS_BAR_CLOCK_DATE_FORMAT = "status_bar_clock_date_format"; /** - * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead + * Statusbar clock background + * 0 - hide accented chip (default) + * 1 - show accented chip + * @hide */ - @Deprecated - public static final String DATA_ROAMING = Global.DATA_ROAMING; + public static final String STATUSBAR_CLOCK_CHIP = "statusbar_clock_chip"; /** - * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead + * Clock chip custom gradient – start + * @hide */ - @Deprecated - public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; + public static final String STATUSBAR_CLOCK_CHIP_GRADIENT_START_COLOR = "statusbar_clock_chip_gradient_start_color"; /** - * @deprecated Use {@link android.provider.Settings.Global#HTTP_PROXY} instead + * Clock chip custom gradient – end + * @hide */ - @Deprecated - public static final String HTTP_PROXY = Global.HTTP_PROXY; + public static final String STATUSBAR_CLOCK_CHIP_GRADIENT_END_COLOR = "statusbar_clock_chip_gradient_end_color"; /** - * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead + * Clock chip custom gradient – angle + * @hide */ - @Deprecated - public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS; + public static final String STATUSBAR_CLOCK_CHIP_GRADIENT_ANGLE = "statusbar_clock_chip_gradient_angle"; /** - * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} - * instead + * Clock chip custom gradient – angle + * @hide */ - @Deprecated - public static final String LOCATION_PROVIDERS_ALLOWED = Secure.LOCATION_PROVIDERS_ALLOWED; + public static final String STATUSBAR_CLOCK_CHIP_GRADIENT_MASK_TEXT = "statusbar_clock_chip_gradient_mask_text"; /** - * @deprecated Use {@link android.provider.Settings.Secure#LOGGING_ID} instead + * Double tap on lockscreen to sleep + * @hide */ - @Deprecated - public static final String LOGGING_ID = Secure.LOGGING_ID; + public static final String DOUBLE_TAP_SLEEP_LOCKSCREEN = "double_tap_sleep_lockscreen"; /** - * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead + * Whether StatusBar icons should use app icon + * @hide */ - @Deprecated - public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; + public static final String STATUSBAR_COLORED_ICONS = "statusbar_colored_icons"; /** - * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED} - * instead + * Show the pending notification counts as overlays on the status bar + * @hide */ - @Deprecated - public static final String PARENTAL_CONTROL_ENABLED = Secure.PARENTAL_CONTROL_ENABLED; + public static final String STATUSBAR_NOTIF_COUNT = "statusbar_notif_count"; /** - * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_LAST_UPDATE} - * instead + * Whether now playing is enabled + * @hide */ - @Deprecated - public static final String PARENTAL_CONTROL_LAST_UPDATE = Secure.PARENTAL_CONTROL_LAST_UPDATE; + public static final String NOWPLAYING_ENABLED = "nowplaying_enabled"; /** - * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_REDIRECT_URL} - * instead + * Whether to use accent color (true) or white (false) + * 0 = White (default), 1 = Accent color + * @hide */ - @Deprecated - public static final String PARENTAL_CONTROL_REDIRECT_URL = - Secure.PARENTAL_CONTROL_REDIRECT_URL; + public static final String NOWPLAYING_USE_ACCENT_COLOR = "nowplaying_use_accent_color"; /** - * @deprecated Use {@link android.provider.Settings.Secure#SETTINGS_CLASSNAME} instead + * Whether to show app icon above track title. + * Shows music app icon or default music note icon. + * @hide */ - @Deprecated - public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME; + public static final String NOWPLAYING_ICON_STYLE = "nowplaying_icon_style"; /** - * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead + * Now playing track icon size + * @hide */ - @Deprecated - public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; + public static final String NOWPLAYING_ICON_SIZE = "nowplaying_icon_size"; /** - * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead + * Whether to use compact single-line style. + * @hide */ - @Deprecated - public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; + public static final String NOWPLAYING_USE_COMPACT_STYLE = "nowplaying_use_compact_style"; - /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead + /** + * Now playing vertical position (0.0 - 1.0) + * @hide */ - @Deprecated - public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; + public static final String NOWPLAYING_VERTICAL_POSITION = "nowplaying_vertical_position"; /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + * Now playing track text size + * @hide */ - @Deprecated - public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = - Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + public static final String NOWPLAYING_TRACK_TEXT_SIZE = "nowplaying_track_text_size"; /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead + * Now playing artist text size + * @hide */ - @Deprecated - public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = - Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; + public static final String NOWPLAYING_ARTIST_TEXT_SIZE = "nowplaying_artist_text_size"; /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead + * Whether to show now playing on AOD + * @hide */ - @Deprecated - public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = - Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; + public static final String NOWPLAYING_SHOW_ON_AOD = "nowplaying_show_on_aod"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT} - * instead + * Whether to show now playing on lockscreen + * @hide */ - @Deprecated - public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT; + public static final String NOWPLAYING_SHOW_ON_LOCKSCREEN = "nowplaying_show_on_lockscreen"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead + * @hide */ - @Deprecated - public static final String WIFI_ON = Global.WIFI_ON; + public static final String SINGLE_QS_TONE_ENABLED = "single_qs_tone_enabled"; /** - * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE} - * instead + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = - Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE; + public static final String DUAL_TARGET_TILE_STYLE = "dual_target_tile_style"; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT} instead + * @hide */ - @Deprecated - public static final String WIFI_WATCHDOG_AP_COUNT = Secure.WIFI_WATCHDOG_AP_COUNT; + public static final String QS_TILE_ALTERNATE_COLOR = "qs_tile_alternate_color"; /** - * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS} instead + * Whether to show the battery bar + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = - Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS; + public static final String STATUSBAR_BATTERY_BAR = "statusbar_battery_bar"; /** - * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = - Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED; + public static final String STATUSBAR_BATTERY_BAR_COLOR = "statusbar_battery_bar_color"; /** - * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS} - * instead + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = - Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS; + public static final String STATUSBAR_BATTERY_BAR_THICKNESS = + "statusbar_battery_bar_thickness"; /** - * @deprecated Use - * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} instead + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = - Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT; + public static final String STATUSBAR_BATTERY_BAR_STYLE = "statusbar_battery_bar_style"; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS} - * instead + * @hide */ - @Deprecated - public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS; + public static final String STATUSBAR_BATTERY_BAR_ANIMATE = "statusbar_battery_bar_animate"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead + * @hide */ - @Deprecated - public static final String WIFI_WATCHDOG_ON = Global.WIFI_WATCHDOG_ON; + public static final String STATUSBAR_BATTERY_BAR_CHARGING_COLOR = + "statusbar_battery_bar_charging_color"; + /** + * @hide + */ + public static final String STATUSBAR_BATTERY_BAR_BATTERY_LOW_COLOR = + "statusbar_battery_bar_battery_low_color"; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead + * @hide */ - @Deprecated - public static final String WIFI_WATCHDOG_PING_COUNT = Secure.WIFI_WATCHDOG_PING_COUNT; + public static final String STATUSBAR_BATTERY_BAR_ENABLE_CHARGING_COLOR = + "statusbar_battery_bar_enable_charging_color"; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS} - * instead + * @hide */ - @Deprecated - public static final String WIFI_WATCHDOG_PING_DELAY_MS = Secure.WIFI_WATCHDOG_PING_DELAY_MS; + public static final String STATUSBAR_BATTERY_BAR_BLEND_COLOR = "statusbar_battery_bar_blend_color"; /** - * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS} - * instead + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = - Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS; + public static final String STATUSBAR_BATTERY_BAR_BLEND_COLOR_REVERSE = + "statusbar_battery_bar_blend_color_reverse"; /** - * Checks if the specified app can modify system settings. As of API - * level 23, an app cannot modify system settings unless it declares the - * {@link android.Manifest.permission#WRITE_SETTINGS} - * permission in its manifest, and the user specifically grants - * the app this capability. To prompt the user to grant this approval, - * the app must send an intent with the action {@link - * android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}, which causes - * the system to display a permission management screen. - * - * @param context App context. - * @return true if the calling app can write to system settings, false otherwise + * Enable/disable Bluetooth Battery bar + * @hide */ - public static boolean canWrite(Context context) { - return isCallingPackageAllowedToWriteSettings(context, Process.myUid(), - context.getOpPackageName(), false); - } - } + public static final String BLUETOOTH_SHOW_BATTERY = "bluetooth_show_battery"; - /** - * Secure system settings, containing system preferences that applications - * can read but are not allowed to write. These are for preferences that - * the user must explicitly modify through the UI of a system app. Normal - * applications cannot modify the secure settings database, either directly - * or by calling the "put" methods that this class contains. - */ - public static final class Secure extends NameValueTable { - // NOTE: If you add new settings here, be sure to add them to - // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoSecureSettingsLocked. + /** + * Statusbar logo + * @hide + */ + public static final String STATUS_BAR_LOGO = "status_bar_logo"; /** - * The content:// style URL for this table + * Position of Status bar logo + * 0 - Left (default) + * 1 - Right + * @hide */ - public static final Uri CONTENT_URI = - Uri.parse("content://" + AUTHORITY + "/secure"); + public static final String STATUS_BAR_LOGO_POSITION = "status_bar_logo_position"; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - private static final ContentProviderHolder sProviderHolder = - new ContentProviderHolder(CONTENT_URI); + /** + * Statusbar logo custom style + * @hide + */ + public static final String STATUS_BAR_LOGO_STYLE = "status_bar_logo_style"; - // Populated lazily, guarded by class object: - @UnsupportedAppUsage - private static final NameValueCache sNameValueCache = new NameValueCache( - CONTENT_URI, - CALL_METHOD_GET_SECURE, - CALL_METHOD_PUT_SECURE, - CALL_METHOD_DELETE_SECURE, - sProviderHolder, - Secure.class); + /** + * Whether to display cross sign for a data disabled connection + * @hide + */ + public static final String DATA_DISABLED_ICON = "data_disabled_icon"; - @UnsupportedAppUsage - private static final HashSet MOVED_TO_LOCK_SETTINGS; - @UnsupportedAppUsage - private static final HashSet MOVED_TO_GLOBAL; - static { - MOVED_TO_LOCK_SETTINGS = new HashSet<>(6); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE); - MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH); + /** + * Whether to display 4G icon instead LTE + * @hide + */ + public static final String SHOW_FOURG_ICON = "show_fourg_icon"; - MOVED_TO_GLOBAL = new HashSet<>(); - MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED); - MOVED_TO_GLOBAL.add(Settings.Global.ASSISTED_GPS_ENABLED); - MOVED_TO_GLOBAL.add(Settings.Global.BLUETOOTH_ON); - MOVED_TO_GLOBAL.add(Settings.Global.CDMA_CELL_BROADCAST_SMS); - MOVED_TO_GLOBAL.add(Settings.Global.CDMA_ROAMING_MODE); - MOVED_TO_GLOBAL.add(Settings.Global.CDMA_SUBSCRIPTION_MODE); - MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE); - MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI); - MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING); - MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); - MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED); - MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED); - MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE); - MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE); - MOVED_TO_GLOBAL.add(Settings.Global.MOBILE_DATA); - MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION); - MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_DELETE_AGE); - MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_PERSIST_BYTES); + /** + * @hide + */ + public static final String DISABLE_STACKED_MOBILE_ICONS = "disable_stacked_mobile_icons"; + + /** + * @hide + */ + public static final String WIFI_STANDARD_ICON = "wifi_standard_icon"; + + /** + * @hide + */ + public static final String STATUSBAR_EXTRA_PADDING_START = "statusbar_extra_padding_start"; + + /** + * @hide + */ + public static final String STATUSBAR_EXTRA_PADDING_TOP = "statusbar_extra_padding_top"; + + /** + * @hide + */ + public static final String STATUSBAR_EXTRA_PADDING_END = "statusbar_extra_padding_end"; + + /** + * Whether to use the custom status bar header or not + * @hide + */ + public static final String STATUS_BAR_CUSTOM_HEADER = "status_bar_custom_header"; + + /** + * Whether to apply a shadow on top of the header image + * value is the alpha value of the shadow image is 0 -> no shadow -> 255 black + * @hide + */ + public static final String STATUS_BAR_CUSTOM_HEADER_SHADOW = "status_bar_custom_header_shadow"; + + /** + * header image package to use for daylight header - package name - null if default + * @hide + */ + public static final String STATUS_BAR_DAYLIGHT_HEADER_PACK = "status_bar_daylight_header_pack"; + + /** + * Current active provider - available currently "static" "daylight" + * @hide + */ + public static final String STATUS_BAR_CUSTOM_HEADER_PROVIDER = "status_bar_custom_header_provider"; + + /** + * Manual override picture to use + * @hide + */ + public static final String STATUS_BAR_CUSTOM_HEADER_IMAGE = "status_bar_custom_header_image"; + + /** + * @hide + */ + public static final String STATUS_BAR_FILE_HEADER_IMAGE = "status_bar_file_header_image"; + + /** + * Header height + * @hide + */ + public static final String STATUS_BAR_CUSTOM_HEADER_HEIGHT = "status_bar_custom_header_height"; + + /** + * Disable hw buttons + * @hide + */ + public static final String HARDWARE_KEYS_DISABLE = "hardware_keys_disable"; + + /** + * @hide + */ + public static final String LOCKSCREEN_WEATHER_ENABLED = "lockscreen_weather_enabled"; + + /** + * @hide + */ + public static final String LOCKSCREEN_WEATHER_LOCATION = "lockscreen_weather_location"; + + /** + * @hide + */ + public static final String LOCKSCREEN_WEATHER_TEXT = "lockscreen_weather_text"; + + /** + * @hide + */ + public static final String LOCKSCREEN_WEATHER_WIND_INFO = "lockscreen_weather_wind_info"; + + /** + * @hide + */ + public static final String LOCKSCREEN_WEATHER_HUMIDITY_INFO = "lockscreen_weather_humidity_info"; + + /** + * Whether to show the battery info on the lockscreen while charging + * @hide + */ + public static final String LOCKSCREEN_BATTERY_INFO = "lockscreen_battery_info"; + + /** + * Whether to enable the ripple animation on fingerprint unlock + * @hide + */ + public static final String ENABLE_RIPPLE_EFFECT = "enable_ripple_effect"; + + /** + * Whether to show power menu on LockScreen + * @hide + */ + public static final String LOCKSCREEN_ENABLE_POWER_MENU = "lockscreen_enable_power_menu"; + + /** + * @hide + */ + public static final String UDFPS_ANIM_STYLE = "udfps_anim_style"; + + /** + * UDFPS animation size (scale 0-100, where 50 = 100% default size) + * @hide + */ + public static final String UDFPS_ANIM_SIZE = "udfps_anim_size"; + + /** + * UDFPS animation vertical offset (-50 to +50 dp from default position) + * @hide + */ + public static final String UDFPS_ANIM_OFFSET = "udfps_anim_offset"; + + /** + * @hide + */ + public static final String UDFPS_ICON = "udfps_icon"; + + /** + * @hide + */ + public static final String UDFPS_ICON_TYPE = "udfps_icon_type"; + + /** + * @hide + */ + public static final String UDFPS_CUSTOM_FP_ICON_PATH = "udfps_custom_fp_icon_path"; + + /** + * @hide + */ + public static final String UDFPS_ICON_AOD = "udfps_icon_aod"; + + /** + * Whether to vibrate on succesful fingerprint authentication + * @hide + */ + public static final String FP_SUCCESS_VIBRATE = "fp_success_vibrate"; + + /** + * Whether to vibrate on unsuccesful fingerprint authentication + * @hide + */ + public static final String FP_ERROR_VIBRATE = "fp_error_vibrate"; + + /** + * @hide + */ + public static final String RECENTS_LOCKED_TASKS = "recents_locked_tasks"; + + /** + * Whether to show the carrier name on the lockscreen + * @hide + */ + public static final String LOCKSCREEN_SHOW_CARRIER = "lockscreen_show_carrier"; + + /** + * Swap capacitive keys + * @hide + */ + public static final String SWAP_CAPACITIVE_KEYS = "swap_capacitive_keys"; + + /** + * Indicates whether ANBI (Accidental navigation button interaction) is enabled. + * @hide + */ + public static final String ANBI_ENABLED = "anbi_enabled"; + + /** + * Whether three fingers swipe is active + * 0 = Inactive, 1 = Active + * @hide + */ + @Readable + public static final String THREE_FINGER_GESTURE_ACTIVE = "three_fingers_swipe_active"; + + /** + * If On-The-Go should be displayed at the power menu. + * @hide + */ + public static final String GLOBAL_ACTIONS_ONTHEGO = "global_actions_onthego"; + + /** + * The alpha value of the On-The-Go overlay. + * @hide + */ + public static final String ON_THE_GO_ALPHA = "on_the_go_alpha"; + + /** + * Whether the service should restart itself or not. + * @hide + */ + public static final String ON_THE_GO_SERVICE_RESTART = "on_the_go_service_restart"; + + /** + * The camera instance to use. + * 0 = Rear Camera + * 1 = Front Camera + * @hide + */ + public static final String ON_THE_GO_CAMERA = "on_the_go_camera"; + + /** + * Whether to show or hide alert slider notifications on supported devices + * @hide + */ + public static final String ALERT_SLIDER_NOTIFICATIONS = "alert_slider_notifications"; + + /** + * Whether to show daily/weekly data usage in the QS footer. + * @hide + */ + public static final String QS_SHOW_DATA_USAGE = "qs_show_data_usage"; + + /** + * Persist setting for showing either daily or weekly data usage in the QS footer. + * @hide + */ + public static final String QS_SHOW_DATA_USAGE_WINDOW = "qs_show_data_usage_window"; + + /** + * Haptic feedback on brightness slider + * @hide + */ + public static final String QS_BRIGHTNESS_SLIDER_HAPTIC = "qs_brightness_slider_haptic"; + + /** + * Customize QS tile shape. + * @hide + */ + public static final String QS_TILE_SHAPE = "qs_tile_shape"; + + /** + * @hide + */ + public static final String QS_TILE_STYLE_MINIMAL = "qs_tile_style_minimal"; + + /** + * @hide + */ + public static final String QS_USE_MODIFIED_TILE_SPACING = "qs_use_modified_tile_spacing"; + + /** + * @hide + */ + public static final String QS_TILE_STYLE_MINIMAL_INVERT = "qs_tile_style_minimal_invert"; + + /** + * Customize Brightness slider shape. + * @hide + */ + public static final String QS_BRIGHTNESS_SLIDER_SHAPE = "qs_brightness_slider_shape"; + + /** + * @hide + */ + public static final String QS_BRIGHTNESS_SLIDER_STYLE = "qs_brightness_slider_style"; + + /** + * Haptic feedback on QS tiles + * @hide + */ + public static final String QS_TILE_HAPTIC = "qs_tile_haptic"; + + /** + * @hide + */ + public static final String QS_TILES_COLUMNS_LANDSCAPE = "qs_tiles_columns_landscape"; + + /** + * @hide + */ + public static final String QS_TILES_COLUMNS = "qs_tiles_columns"; + + /** + * @hide + */ + public static final String QS_TILES_ROWS_LANDSCAPE = "qs_tiles_rows_landscape"; + + /** + * @hide + */ + public static final String QS_TILES_ROWS = "qs_tiles_rows"; + + /** + * @hide + */ + public static final String QQS_TILES_ROWS_LANDSCAPE = "qqs_tiles_rows_landscape"; + + /** + * @hide + */ + public static final String QQS_TILES_ROWS = "qqs_tiles_rows"; + + /** + * Lockscreen Media Art + * @hide + */ + public static final String LS_MEDIA_ART_ENABLED = "ls_media_art_enabled"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_FILTER = "ls_media_art_filter"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_FADE_LEVEL = "ls_media_art_fade_level"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_BLUR_LEVEL = "ls_media_art_blur_level"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_PIXEL_SIZE = "ls_media_art_pixel_size"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_AOD_ENABLED = "ls_media_art_aod_enabled"; + + /** + * @hide + */ + public static final String LS_MEDIA_ART_AOD_DIM_LEVEL = "ls_media_art_aod_dim_level"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_CHANGE_ON = "lock_glymps_change_on"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_TIMER_INTERVAL = "lock_glymps_timer_interval"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_WALLPAPER_TARGET = "lock_glymps_wallpaper_target"; + + /** + * Whether edge light is enabled + * @hide + */ + public static final String EDGE_LIGHT_ENABLED = "edge_light_enabled"; + + /** + * Color mode of edge light + * @hide + */ + public static final String EDGE_LIGHT_COLOR_MODE = "edge_light_color_mode"; + + /** + * Custom color (hex value) for edge light + * @hide + */ + public static final String EDGE_LIGHT_CUSTOM_COLOR = "edge_light_custom_color"; + + /** + * Pulse count for edge light + * @hide + */ + public static final String EDGE_LIGHT_PULSE_COUNT = "edge_light_pulse_count"; + + /** + * Stroke width for edge light + * @hide + */ + public static final String EDGE_LIGHT_STROKE_WIDTH = "edge_light_stroke_width"; + + /** + * Edge light style + * @hide + */ + public static final String EDGE_LIGHT_STYLE = "edge_light_style"; + + /** + * Edge light animation effect type + * @hide + */ + public static final String EDGE_LIGHT_ANIMATION_EFFECT = "edge_light_animation_effect"; + + /** + * Lock Glymps - Dynamic lock screen wallpaper feature + * @hide + */ + public static final String LOCK_GLYMPS_ENABLED = "lock_glymps_enabled"; + + /** + * Lock Glymps wallpaper source (0=Random, 1=Custom URLs) + * @hide + */ + public static final String LOCK_GLYMPS_SOURCE = "lock_glymps_source"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_WIFI_ONLY = "lock_glymps_wifi_only"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_CACHE_SIZE = "lock_glymps_cache_size"; + + /** + * @hide + */ + public static final String LOCK_GLYMPS_CUSTOM_URLS = "lock_glymps_custom_urls"; + + /** + * Gesture navbar length mode. + * Supported modes: 0 for short length, 1 for normal and 2 for long. + * @hide + */ + public static final String GESTURE_NAVBAR_LENGTH_MODE = "gesture_navbar_length_mode"; + + /** @hide */ + public static final String BACK_GESTURE_HEIGHT = "back_gesture_height"; + + /** + * @hide + */ + public static final String GESTURE_NAVBAR_HEIGHT_MODE = "gesture_navbar_height_mode"; + + /** + * Whether allowing pocket service to register sensors and dispatch informations. + * 0 = disabled + * 1 = enabled + * @hide + */ + public static final String POCKET_JUDGE = "pocket_judge"; + + /** + * Whether to show heads up only for dialer and sms apps + * @hide + */ + public static final String LESS_BORING_HEADS_UP = "less_boring_heads_up"; + + /** + * Whether to play notification sound and vibration if screen is ON + * 0 - never + * 1 - always + * @hide + */ + public static final String NOTIFICATION_SOUND_VIB_SCREEN_ON = "notification_sound_vib_screen_on"; + + /** + * Tint statusbar icons with system accent color + * @hide + */ + public static final String TINT_STATUSBAR_ICONS_WITH_ACCENT = "tint_statusbar_icons_with_accent"; + + /** + * Heads up timeout configuration + * @hide + */ + public static final String HEADS_UP_TIMEOUT = "heads_up_timeout"; + + /** + * Whether to show the kill app button in notification guts + * @hide + */ + public static final String NOTIFICATION_GUTS_KILL_APP_BUTTON = + "notification_guts_kill_app_button"; + + /** + * Show app volume rows in volume panel + * @hide + */ + public static final String SHOW_APP_VOLUME = "show_app_volume"; + + /** + * Per-app refresh rate config + * @hide + */ + public static final String REFRESH_RATE_CONFIG_CUSTOM = "refresh_rate_config_custom"; + + /** + * Force highest refresh rate in all apps + * @hide + */ + public static final String EXTREME_REFRESH_RATE = "extreme_refresh_rate"; + + /** + * Whether to show volume percentage in volume panel + * @hide + */ + public static final String SHOW_VOLUME_PERCENTAGE = "show_volume_percentage"; + + /** + * Whether to show charging animation + * @hide + */ + public static final String CHARGING_ANIMATION = "charging_animation"; + + /** + * Force full screen for devices with cutout + * @hide + */ + public static final String FORCE_FULLSCREEN_CUTOUT_APPS = "force_full_screen_cutout_apps"; + + /** + * Defines the screen-off animation to display + * @hide + */ + public static final String SCREEN_OFF_ANIMATION = "screen_off_animation"; + + /** + * @hide + */ + public static final String MEDIA_WAVEFORM_SEEKBAR = "media_waveform_seekbar"; + + /** + * Whether to show rotation suggestion + * @hide + */ + @Readable + public static final String ENABLE_ROTATION_BUTTON = "enable_rotation_button"; + + /** + * @hide + */ + public static final String SCREENSHOT_SHUTTER_SOUND = "screenshot_shutter_sound"; + + /** + * Use dynamic color based on battery level + * @hide + */ + public static final String WIRELESS_CHARGING_DYNAMIC_COLOR = "wireless_charging_dynamic_color"; + + /** + * Charging ripple shape + * @hide + */ + public static final String WIRELESS_CHARGING_RIPPLE_SHAPE = "wireless_charging_ripple_shape"; + + /** + * @hide + */ + @Readable + public static final String EDGE_SCROLLING_HAPTICS_INTENSITY = "edge_scrolling_haptics_intensity"; + + /** + * What to show at the bottom of the Ambient display + * 0: Nothing. + * 1: Battery Percentage. + * 2: Battery Temperature. + * 3: Battery Percentage & Temperature Together. + * @hide + */ + public static final String AMBIENT_SHOW_SETTINGS = "ambient_show_settings"; + + /** + * Ambient settings show icons + * @hide + */ + public static final String AMBIENT_SHOW_SETTINGS_ICONS = "ambient_show_settings_icons"; + + /** + * Whether to unlimit screenrecord filesize + * Not for backup - dev option + * @hide + */ + @Readable + public static final String UNLIMIT_SCREENRECORD = "unlimit_screenrecord"; + + /** + * Gradient on QS tiles + * @hide + */ + public static final String QS_TILE_GRADIENT = "qs_tile_gradient"; + + /** + * Gradient on QS brightness slider + * @hide + */ + public static final String QS_BRIGHTNESS_SLIDER_GRADIENT = "qs_brightness_slider_gradient"; + + /** + * Gradient on Volume slider + * @hide + */ + public static final String VOLUME_SLIDER_GRADIENT = "volume_slider_gradient"; + + /** + * Gradient color mode + * @hide + */ + public static final String CUSTOM_GRADIENT_COLOR_MODE = "custom_gradient_color_mode"; + + /** + * Gradient start color + * @hide + */ + public static final String CUSTOM_GRADIENT_START_COLOR = "custom_gradient_start_color"; + + /** + * Gradient end color + * @hide + */ + public static final String CUSTOM_GRADIENT_END_COLOR = "custom_gradient_end_color"; + + /** + * Whether to use classic QS panel style for tiles + * @hide + */ + public static final String QS_PANEL_STYLE = "qs_panel_style"; + + /** + * Whether to hide label under tiles in classic QS panel style + * @hide + */ + public static final String QS_TILE_LABEL_HIDE = "qs_tile_label_hide"; + + /** + * Select tile shape for classic QS panel style + * @hide + */ + public static final String QS_TILE_ICON_SHAPE = "qs_tile_icon_shape"; + + /** + * Keys we no longer back up under the current schema, but want to continue to + * process when restoring historical backup datasets. + * + * All settings in {@link LEGACY_RESTORE_SETTINGS} array *must* have a non-null validator, + * otherwise they won't be restored. + * + * @hide + */ + public static final String[] LEGACY_RESTORE_SETTINGS = { + }; + + /** + * These are all public system settings + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final Set PUBLIC_SETTINGS = new ArraySet<>(); + static { + PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR); + PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP); + PUBLIC_SETTINGS.add(WIFI_STATIC_IP); + PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY); + PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK); + PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1); + PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2); + PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY); + PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT); + PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED); + PUBLIC_SETTINGS.add(FONT_SCALE); + PUBLIC_SETTINGS.add(SYSTEM_LOCALES); + PUBLIC_SETTINGS.add(DIM_SCREEN); + PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT); + PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS); + PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE); + PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED); + PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED); + PUBLIC_SETTINGS.add(VIBRATE_ON); + PUBLIC_SETTINGS.add(VOLUME_RING); + PUBLIC_SETTINGS.add(VOLUME_SYSTEM); + PUBLIC_SETTINGS.add(VOLUME_VOICE); + PUBLIC_SETTINGS.add(VOLUME_MUSIC); + PUBLIC_SETTINGS.add(VOLUME_ALARM); + PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION); + PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO); + PUBLIC_SETTINGS.add(VOLUME_ASSISTANT); + PUBLIC_SETTINGS.add(RINGTONE); + PUBLIC_SETTINGS.add(RINGTONE2); + PUBLIC_SETTINGS.add(NOTIFICATION_SOUND); + PUBLIC_SETTINGS.add(ALARM_ALERT); + PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE); + PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS); + PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE); + PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD); + PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS); + PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY); + PUBLIC_SETTINGS.add(TIME_12_24); + PUBLIC_SETTINGS.add(DATE_FORMAT); + PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN); + PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION); + PUBLIC_SETTINGS.add(USER_ROTATION); + PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING); + PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED); + PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED); + PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS); + PUBLIC_SETTINGS.add(VIBRATE_WHEN_RINGING); + PUBLIC_SETTINGS.add(APPLY_RAMPING_RINGER); + } + + /** + * These are all hidden system settings. + * + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final Set PRIVATE_SETTINGS = new ArraySet<>(); + static { + PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP); + PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR); + PRIVATE_SETTINGS.add(ADVANCED_SETTINGS); + PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_DISABLE); + PRIVATE_SETTINGS.add(ACCESSIBILITY_FORCE_INVERT_COLOR_OVERRIDE_PACKAGES_TO_ENABLE); + PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED); + PRIVATE_SETTINGS.add(WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE); + PRIVATE_SETTINGS.add(WEAR_TTS_PREWARM_ENABLED); + PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ); + PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES); + PRIVATE_SETTINGS.add(VOLUME_MASTER); + PRIVATE_SETTINGS.add(MASTER_MONO); + PRIVATE_SETTINGS.add(MASTER_BALANCE); + PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME); + PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT); + PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER); + PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY); + PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING); + PRIVATE_SETTINGS.add(HEARING_AID_COMPATIBILITY); + PRIVATE_SETTINGS.add(TTY_MODE); + PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE); + PRIVATE_SETTINGS.add(POINTER_LOCATION); + PRIVATE_SETTINGS.add(SHOW_TOUCHES); + PRIVATE_SETTINGS.add(SHOW_KEY_PRESSES); + PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG); + PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED); + PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED); + PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED); + PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED); + PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND); + PRIVATE_SETTINGS.add(DESK_DOCK_SOUND); + PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND); + PRIVATE_SETTINGS.add(CAR_DOCK_SOUND); + PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND); + PRIVATE_SETTINGS.add(LOCK_SOUND); + PRIVATE_SETTINGS.add(UNLOCK_SOUND); + PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS); + PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS); + PRIVATE_SETTINGS.add(SIP_ALWAYS); + PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY); + PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME); + PRIVATE_SETTINGS.add(POINTER_SPEED); + PRIVATE_SETTINGS.add(POINTER_FILL_STYLE); + PRIVATE_SETTINGS.add(POINTER_STROKE_STYLE); + PRIVATE_SETTINGS.add(POINTER_SCALE); + PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED); + PRIVATE_SETTINGS.add(EGG_MODE); + PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT); + PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE); + PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE_VENDOR_HINT); + PRIVATE_SETTINGS.add(LOCALE_PREFERENCES); + PRIVATE_SETTINGS.add(TOUCHPAD_POINTER_SPEED); + PRIVATE_SETTINGS.add(TOUCHPAD_NATURAL_SCROLLING); + PRIVATE_SETTINGS.add(TOUCHPAD_TAP_TO_CLICK); + PRIVATE_SETTINGS.add(TOUCHPAD_TAP_DRAGGING); + PRIVATE_SETTINGS.add(TOUCHPAD_RIGHT_CLICK_ZONE); + PRIVATE_SETTINGS.add(TOUCHPAD_SYSTEM_GESTURES); + PRIVATE_SETTINGS.add(TOUCHPAD_ACCELERATION_ENABLED); + PRIVATE_SETTINGS.add(TOUCHPAD_ENABLED); + PRIVATE_SETTINGS.add(CAMERA_FLASH_NOTIFICATION); + PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION); + PRIVATE_SETTINGS.add(SCREEN_FLASH_NOTIFICATION_COLOR); + PRIVATE_SETTINGS.add(DEFAULT_DEVICE_FONT_SCALE); + PRIVATE_SETTINGS.add(MOUSE_REVERSE_VERTICAL_SCROLLING); + PRIVATE_SETTINGS.add(MOUSE_SWAP_PRIMARY_BUTTON); + PRIVATE_SETTINGS.add(MOUSE_POINTER_ACCELERATION_ENABLED); + PRIVATE_SETTINGS.add(PREFERRED_REGION); + PRIVATE_SETTINGS.add(MOUSE_SCROLLING_ACCELERATION); + PRIVATE_SETTINGS.add(MOUSE_SCROLLING_SPEED); + } + + /** + * These entries are considered common between the personal and the managed profile, + * since the managed profile doesn't get to change them. + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private static final Set CLONE_TO_MANAGED_PROFILE = new ArraySet<>(); + static { + CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT); + CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED); + CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED); + CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD); + CLONE_TO_MANAGED_PROFILE.add(TIME_12_24); + } + + /** @hide */ + public static void getCloneToManagedProfileSettings(Set outKeySet) { + outKeySet.addAll(CLONE_TO_MANAGED_PROFILE); + } + + /** + * These entries should be cloned from this profile's parent only if the dependency's + * value is true ("1") + * + * Note: the dependencies must be Secure settings + * + * @hide + */ + public static final Map CLONE_FROM_PARENT_ON_VALUE = new ArrayMap<>(); + static { + CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE, Secure.SYNC_PARENT_SOUNDS); + CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE2, Secure.SYNC_PARENT_SOUNDS); + CLONE_FROM_PARENT_ON_VALUE.put(NOTIFICATION_SOUND, Secure.SYNC_PARENT_SOUNDS); + CLONE_FROM_PARENT_ON_VALUE.put(ALARM_ALERT, Secure.SYNC_PARENT_SOUNDS); + } + + /** @hide */ + public static void getCloneFromParentOnValueSettings(Map outMap) { + outMap.putAll(CLONE_FROM_PARENT_ON_VALUE); + } + + /** + * System settings which can be accessed by instant apps. + * @hide + */ + public static final Set INSTANT_APP_SETTINGS = new ArraySet<>(); + static { + INSTANT_APP_SETTINGS.add(TEXT_AUTO_REPLACE); + INSTANT_APP_SETTINGS.add(TEXT_AUTO_CAPS); + INSTANT_APP_SETTINGS.add(TEXT_AUTO_PUNCTUATE); + INSTANT_APP_SETTINGS.add(TEXT_SHOW_PASSWORD); + INSTANT_APP_SETTINGS.add(DATE_FORMAT); + INSTANT_APP_SETTINGS.add(FONT_SCALE); + INSTANT_APP_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED); + INSTANT_APP_SETTINGS.add(TIME_12_24); + INSTANT_APP_SETTINGS.add(SOUND_EFFECTS_ENABLED); + INSTANT_APP_SETTINGS.add(ACCELEROMETER_ROTATION); + } + + /** + * When to use Wi-Fi calling + * + * @see android.telephony.TelephonyManager.WifiCallingChoices + * @hide + */ + @Readable + public static final String WHEN_TO_MAKE_WIFI_CALLS = "when_to_make_wifi_calls"; + + /** Controls whether bluetooth is on or off on wearable devices. + * + *

The valid values for this key are: 0 (disabled) or 1 (enabled). + * + * @hide + */ + public static final String CLOCKWORK_BLUETOOTH_SETTINGS_PREF = "cw_bt_settings_pref"; + + /** + * Controls whether the unread notification dot indicator is shown on wearable devices. + * + *

The valid values for this key are: 0 (disabled) or 1 (enabled). + * + * @hide + */ + public static final String UNREAD_NOTIFICATION_DOT_INDICATOR = + "unread_notification_dot_indicator"; + + /** + * Controls whether auto-launching media controls is enabled on wearable devices. + * + *

The valid values for this key are: 0 (disabled) or 1 (enabled). + * + * @hide + */ + public static final String AUTO_LAUNCH_MEDIA_CONTROLS = "auto_launch_media_controls"; + + // Settings moved to Settings.Secure + + /** + * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} + * instead + */ + @Deprecated + public static final String ADB_ENABLED = Global.ADB_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#ANDROID_ID} instead + */ + @Deprecated + public static final String ANDROID_ID = Secure.ANDROID_ID; + + /** + * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead + */ + @Deprecated + public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; + + /** + * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead + */ + @Deprecated + public static final String DATA_ROAMING = Global.DATA_ROAMING; + + /** + * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead + */ + @Deprecated + public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; + + /** + * @deprecated Use {@link android.provider.Settings.Global#HTTP_PROXY} instead + */ + @Deprecated + public static final String HTTP_PROXY = Global.HTTP_PROXY; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#INSTALL_NON_MARKET_APPS} instead + */ + @Deprecated + public static final String INSTALL_NON_MARKET_APPS = Secure.INSTALL_NON_MARKET_APPS; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#LOCATION_PROVIDERS_ALLOWED} + * instead + */ + @Deprecated + public static final String LOCATION_PROVIDERS_ALLOWED = Secure.LOCATION_PROVIDERS_ALLOWED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#LOGGING_ID} instead + */ + @Deprecated + public static final String LOGGING_ID = Secure.LOGGING_ID; + + /** + * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead + */ + @Deprecated + public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_ENABLED} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_ENABLED = Secure.PARENTAL_CONTROL_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_LAST_UPDATE} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_LAST_UPDATE = Secure.PARENTAL_CONTROL_LAST_UPDATE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#PARENTAL_CONTROL_REDIRECT_URL} + * instead + */ + @Deprecated + public static final String PARENTAL_CONTROL_REDIRECT_URL = + Secure.PARENTAL_CONTROL_REDIRECT_URL; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#SETTINGS_CLASSNAME} instead + */ + @Deprecated + public static final String SETTINGS_CLASSNAME = Secure.SETTINGS_CLASSNAME; + + /** + * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead + */ + @Deprecated + public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; + + /** + * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead + */ + @Deprecated + public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; + + /** + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead + */ + @Deprecated + public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; + + /** + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + */ + @Deprecated + public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = + Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} instead + */ + @Deprecated + public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = + Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; + + /** + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} instead + */ + @Deprecated + public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = + Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; + + /** + * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT} + * instead + */ + @Deprecated + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = Global.WIFI_NUM_OPEN_NETWORKS_KEPT; + + /** + * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} instead + */ + @Deprecated + public static final String WIFI_ON = Global.WIFI_ON; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE} + * instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = + Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_AP_COUNT = Secure.WIFI_WATCHDOG_AP_COUNT; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS} instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED} instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS} + * instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = + Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS; + + /** + * @deprecated Use + * {@link android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = + Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = Secure.WIFI_WATCHDOG_MAX_AP_CHECKS; + + /** + * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_ON = Global.WIFI_WATCHDOG_ON; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT} instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_PING_COUNT = Secure.WIFI_WATCHDOG_PING_COUNT; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS} + * instead + */ + @Deprecated + public static final String WIFI_WATCHDOG_PING_DELAY_MS = Secure.WIFI_WATCHDOG_PING_DELAY_MS; + + /** + * @deprecated Use {@link android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS} + * instead + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = + Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS; + + /** + * Checks if the specified app can modify system settings. As of API + * level 23, an app cannot modify system settings unless it declares the + * {@link android.Manifest.permission#WRITE_SETTINGS} + * permission in its manifest, and the user specifically grants + * the app this capability. To prompt the user to grant this approval, + * the app must send an intent with the action {@link + * android.provider.Settings#ACTION_MANAGE_WRITE_SETTINGS}, which causes + * the system to display a permission management screen. + * + * @param context App context. + * @return true if the calling app can write to system settings, false otherwise + */ + public static boolean canWrite(Context context) { + return isCallingPackageAllowedToWriteSettings(context, Process.myUid(), + context.getOpPackageName(), false); + } + } + + /** + * Secure system settings, containing system preferences that applications + * can read but are not allowed to write. These are for preferences that + * the user must explicitly modify through the UI of a system app. Normal + * applications cannot modify the secure settings database, either directly + * or by calling the "put" methods that this class contains. + */ + public static final class Secure extends NameValueTable { + // NOTE: If you add new settings here, be sure to add them to + // com.android.providers.settings.SettingsProtoDumpUtil#dumpProtoSecureSettingsLocked. + + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = + Uri.parse("content://" + AUTHORITY + "/secure"); + + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + private static final ContentProviderHolder sProviderHolder = + new ContentProviderHolder(CONTENT_URI); + + // Populated lazily, guarded by class object: + @UnsupportedAppUsage + private static final NameValueCache sNameValueCache = new NameValueCache( + CONTENT_URI, + CALL_METHOD_GET_SECURE, + CALL_METHOD_PUT_SECURE, + CALL_METHOD_DELETE_SECURE, + sProviderHolder, + Secure.class); + + @UnsupportedAppUsage + private static final HashSet MOVED_TO_LOCK_SETTINGS; + @UnsupportedAppUsage + private static final HashSet MOVED_TO_GLOBAL; + static { + MOVED_TO_LOCK_SETTINGS = new HashSet<>(6); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_ENABLED); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_VISIBLE); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_PATTERN_SIZE); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_DOTS_VISIBLE); + MOVED_TO_LOCK_SETTINGS.add(Secure.LOCK_SHOW_ERROR_PATH); + + MOVED_TO_GLOBAL = new HashSet<>(); + MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.ASSISTED_GPS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.BLUETOOTH_ON); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_CELL_BROADCAST_SMS); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_ROAMING_MODE); + MOVED_TO_GLOBAL.add(Settings.Global.CDMA_SUBSCRIPTION_MODE); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI); + MOVED_TO_GLOBAL.add(Settings.Global.DATA_ROAMING); + MOVED_TO_GLOBAL.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); + MOVED_TO_GLOBAL.add(Settings.Global.DEVICE_PROVISIONED); + MOVED_TO_GLOBAL.add(Settings.Global.DISPLAY_SIZE_FORCED); + MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE); + MOVED_TO_GLOBAL.add(Settings.Global.MOBILE_DATA); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_BUCKET_DURATION); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_DELETE_AGE); + MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_PERSIST_BYTES); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_DEV_ROTATE_AGE); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES); @@ -7384,5955 +8417,6405 @@ public static final class Secure extends NameValueTable { MOVED_TO_GLOBAL.add(Settings.Global.SECURE_FRP_MODE); } - /** @hide */ - public static void getMovedToGlobalSettings(Set outKeySet) { - outKeySet.addAll(MOVED_TO_GLOBAL); + /** @hide */ + public static void getMovedToGlobalSettings(Set outKeySet) { + outKeySet.addAll(MOVED_TO_GLOBAL); + } + + /** @hide */ + public static void getMovedToSystemSettings(Set outKeySet) { + } + + /** @hide */ + public static void clearProviderForTest() { + sProviderHolder.clearProviderForTest(); + sNameValueCache.clearGenerationTrackerForTest(); + } + + /** @hide */ + public static void getPublicSettings(Set allKeys, Set readableKeys, + ArrayMap readableKeysWithMaxTargetSdk) { + getPublicSettingsForClass(Secure.class, allKeys, readableKeys, + readableKeysWithMaxTargetSdk); + } + + /** + * Look up a name in the database. + * @param resolver to access the database with + * @param name to look up in the table + * @return the corresponding value, or null if not present + */ + public static String getString(ContentResolver resolver, String name) { + return getStringForUser(resolver, name, resolver.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage + public static String getStringForUser(ContentResolver resolver, String name, + @CanBeCURRENT @UserIdInt int userId) { + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + + " to android.provider.Settings.Global."); + return Global.getStringForUser(resolver, name, userId); + } + + if (MOVED_TO_LOCK_SETTINGS.contains(name) && Process.myUid() != Process.SYSTEM_UID) { + // No context; use the ActivityThread's context as an approximation for + // determining the target API level. + Application application = ActivityThread.currentApplication(); + + boolean isPreMnc = application != null + && application.getApplicationInfo() != null + && application.getApplicationInfo().targetSdkVersion + <= VERSION_CODES.LOLLIPOP_MR1; + if (isPreMnc) { + // Old apps used to get the three deprecated LOCK_PATTERN_* settings from + // ILockSettings.getString(). For security reasons, we now just return a + // stubbed-out value. Note: the only one of these three settings actually known + // to have been used was LOCK_PATTERN_ENABLED, and ILockSettings.getString() + // already always returned "0" for that starting in Android 11. + return "0"; + } + throw new SecurityException("Settings.Secure." + name + " is deprecated and no" + + " longer accessible. See API documentation for potential replacements."); + } + + return sNameValueCache.getStringForUser(resolver, name, userId); + } + + /** + * Store a name/value pair into the database. Values written by this method will be + * overridden if a restore happens in the future. + * + * @param resolver to access the database with + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + * + * @hide + */ + @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) + public static boolean putString(ContentResolver resolver, String name, + String value, boolean overrideableByRestore) { + return putStringForUser(resolver, name, value, /* tag */ null, /* makeDefault */ false, + resolver.getUserId(), overrideableByRestore); + } + + /** + * Store a name/value pair into the database. + * @param resolver to access the database with + * @param name to store + * @param value to associate with the name + * @return true if the value was set, false on database errors + */ + public static boolean putString(ContentResolver resolver, String name, String value) { + return putStringForUser(resolver, name, value, resolver.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage + public static boolean putStringForUser(ContentResolver resolver, String name, String value, + @CanBeCURRENT @UserIdInt int userId) { + return putStringForUser(resolver, name, value, null, false, userId, + DEFAULT_OVERRIDEABLE_BY_RESTORE); + } + + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static boolean putStringForUser(@NonNull ContentResolver resolver, + @NonNull String name, @Nullable String value, @Nullable String tag, + boolean makeDefault, @CanBeCURRENT @UserIdInt int userId, + boolean overrideableByRestore) { + if (LOCAL_LOGV) { + Log.v(TAG, "Secure.putString(name=" + name + ", value=" + value + ") for " + + userId); + } + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + + " to android.provider.Settings.Global"); + return Global.putStringForUser(resolver, name, value, + tag, makeDefault, userId, DEFAULT_OVERRIDEABLE_BY_RESTORE); + } + return sNameValueCache.putStringForUser(resolver, name, value, tag, + makeDefault, userId, overrideableByRestore); + } + + /** + * Store a name/value pair into the database. + *

+ * The method takes an optional tag to associate with the setting + * which can be used to clear only settings made by your package and + * associated with this tag by passing the tag to {@link + * #resetToDefaults(ContentResolver, String)}. Anyone can override + * the current tag. Also if another package changes the setting + * then the tag will be set to the one specified in the set call + * which can be null. Also any of the settings setters that do not + * take a tag as an argument effectively clears the tag. + *

+ * For example, if you set settings A and B with tags T1 and T2 and + * another app changes setting A (potentially to the same value), it + * can assign to it a tag T3 (note that now the package that changed + * the setting is not yours). Now if you reset your changes for T1 and + * T2 only setting B will be reset and A not (as it was changed by + * another package) but since A did not change you are in the desired + * initial state. Now if the other app changes the value of A (assuming + * you registered an observer in the beginning) you would detect that + * the setting was changed by another app and handle this appropriately + * (ignore, set back to some value, etc). + *

+ * Also the method takes an argument whether to make the value the + * default for this setting. If the system already specified a default + * value, then the one passed in here will not + * be set as the default. + *

+ * + * @param resolver to access the database with. + * @param name to store. + * @param value to associate with the name. + * @param tag to associate with the setting. + * @param makeDefault whether to make the value the default one. + * @return true if the value was set, false on database errors. + * + * @see #resetToDefaults(ContentResolver, String) + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static boolean putString(@NonNull ContentResolver resolver, + @NonNull String name, @Nullable String value, @Nullable String tag, + boolean makeDefault) { + return putStringForUser(resolver, name, value, tag, makeDefault, + resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE); + } + + /** + * Reset the settings to their defaults. This would reset only + * settings set by the caller's package. Think of it of a way to undo your own + * changes to the global settings. Passing in the optional tag will reset only + * settings changed by your package and associated with this tag. + * + * @param resolver Handle to the content resolver. + * @param tag Optional tag which should be associated with the settings to reset. + * + * @see #putString(ContentResolver, String, String, String, boolean) + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static void resetToDefaults(@NonNull ContentResolver resolver, + @Nullable String tag) { + resetToDefaultsAsUser(resolver, tag, RESET_MODE_PACKAGE_DEFAULTS, + resolver.getUserId()); + } + + /** + * + * Reset the settings to their defaults for a given user with a specific mode. The + * optional tag argument is valid only for {@link #RESET_MODE_PACKAGE_DEFAULTS} + * allowing resetting the settings made by a package and associated with the tag. + * + * @param resolver Handle to the content resolver. + * @param tag Optional tag which should be associated with the settings to reset. + * @param mode The reset mode. + * @param userId The user for which to reset to defaults. + * + * @see #RESET_MODE_PACKAGE_DEFAULTS + * @see #RESET_MODE_UNTRUSTED_DEFAULTS + * @see #RESET_MODE_UNTRUSTED_CHANGES + * @see #RESET_MODE_TRUSTED_DEFAULTS + * + * @hide + */ + public static void resetToDefaultsAsUser(@NonNull ContentResolver resolver, + @Nullable String tag, @ResetMode int mode, + @IntRange(from = 0) @CannotBeSpecialUser @UserIdInt int userId) { + try { + Bundle arg = new Bundle(); + arg.putInt(CALL_METHOD_USER_KEY, userId); + if (tag != null) { + arg.putString(CALL_METHOD_TAG_KEY, tag); + } + arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode); + IContentProvider cp = sProviderHolder.getProvider(resolver); + if (cp == null) { + Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI + + " because cp is null"); + return; + } + cp.call(resolver.getAttributionSource(), + sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg); + } catch (RemoteException e) { + Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e); + } + } + + /** + * Construct the content URI for a particular name/value pair, + * useful for monitoring changes with a ContentObserver. + * @param name to look up in the table + * @return the corresponding content URI, or null if not present + */ + public static Uri getUriFor(String name) { + if (MOVED_TO_GLOBAL.contains(name)) { + Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" + + " to android.provider.Settings.Global, returning global URI."); + return Global.getUriFor(Global.CONTENT_URI, name); + } + return getUriFor(CONTENT_URI, name); + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. The default value will be returned if the setting is + * not defined or not an integer. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid integer. + */ + public static int getInt(ContentResolver cr, String name, int def) { + return getIntForUser(cr, name, def, cr.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage + public static int getIntForUser(ContentResolver cr, String name, int def, + @CanBeCURRENT @UserIdInt int userId) { + String v = getStringForUser(cr, name, userId); + return parseIntSettingWithDefault(v, def); + } + + /** + * Convenience function for retrieving a single secure settings value + * as an integer. Note that internally setting values are always + * stored as strings; this function converts the string to an integer + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + * + * @return The setting's current value. + */ + public static int getInt(ContentResolver cr, String name) + throws SettingNotFoundException { + return getIntForUser(cr, name, cr.getUserId()); + } + + /** @hide */ + public static int getIntForUser(ContentResolver cr, String name, + @CanBeCURRENT @UserIdInt int userId) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userId); + return parseIntSetting(v, name); + } + + /** + * Convenience function for updating a single settings value as an + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putInt(ContentResolver cr, String name, int value) { + return putIntForUser(cr, name, value, cr.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage + public static boolean putIntForUser(ContentResolver cr, String name, int value, + @CanBeCURRENT @UserIdInt int userId) { + return putStringForUser(cr, name, Integer.toString(value), userId); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. The default value will be returned if the setting is + * not defined or not a {@code long}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid {@code long}. + */ + public static long getLong(ContentResolver cr, String name, long def) { + return getLongForUser(cr, name, def, cr.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static long getLongForUser(ContentResolver cr, String name, long def, + @CanBeCURRENT @UserIdInt int userId) { + String v = getStringForUser(cr, name, userId); + return parseLongSettingWithDefault(v, def); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a {@code long}. Note that internally setting values are always + * stored as strings; this function converts the string to a {@code long} + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @return The setting's current value. + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + */ + public static long getLong(ContentResolver cr, String name) + throws SettingNotFoundException { + return getLongForUser(cr, name, cr.getUserId()); + } + + /** @hide */ + public static long getLongForUser(ContentResolver cr, String name, + @CanBeCURRENT @UserIdInt int userId) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userId); + return parseLongSetting(v, name); + } + + /** + * Convenience function for updating a secure settings value as a long + * integer. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putLong(ContentResolver cr, String name, long value) { + return putLongForUser(cr, name, value, cr.getUserId()); + } + + /** @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static boolean putLongForUser(ContentResolver cr, String name, long value, + @CanBeCURRENT @UserIdInt int userId) { + return putStringForUser(cr, name, Long.toString(value), userId); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a floating point number. Note that internally setting values are + * always stored as strings; this function converts the string to an + * float for you. The default value will be returned if the setting + * is not defined or not a valid float. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param def Value to return if the setting is not defined. + * + * @return The setting's current value, or 'def' if it is not defined + * or not a valid float. + */ + public static float getFloat(ContentResolver cr, String name, float def) { + return getFloatForUser(cr, name, def, cr.getUserId()); + } + + /** @hide */ + public static float getFloatForUser(ContentResolver cr, String name, float def, + @CanBeCURRENT @UserIdInt int userId) { + String v = getStringForUser(cr, name, userId); + return parseFloatSettingWithDefault(v, def); + } + + /** + * Convenience function for retrieving a single secure settings value + * as a float. Note that internally setting values are always + * stored as strings; this function converts the string to a float + * for you. + *

+ * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not a float. + * + * @return The setting's current value. + */ + public static float getFloat(ContentResolver cr, String name) + throws SettingNotFoundException { + return getFloatForUser(cr, name, cr.getUserId()); } /** @hide */ - public static void getMovedToSystemSettings(Set outKeySet) { + public static float getFloatForUser(ContentResolver cr, String name, + @CanBeCURRENT @UserIdInt int userId) + throws SettingNotFoundException { + String v = getStringForUser(cr, name, userId); + return parseFloatSetting(v, name); } - /** @hide */ - public static void clearProviderForTest() { - sProviderHolder.clearProviderForTest(); - sNameValueCache.clearGenerationTrackerForTest(); + /** + * Convenience function for updating a single settings value as a + * floating point number. This will either create a new entry in the + * table if the given name does not exist, or modify the value of the + * existing row with that name. Note that internally setting values + * are always stored as strings, so this function converts the given + * value to a string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param value The new value for the setting. + * @return true if the value was set, false on database errors + */ + public static boolean putFloat(ContentResolver cr, String name, float value) { + return putFloatForUser(cr, name, value, cr.getUserId()); } /** @hide */ - public static void getPublicSettings(Set allKeys, Set readableKeys, - ArrayMap readableKeysWithMaxTargetSdk) { - getPublicSettingsForClass(Secure.class, allKeys, readableKeys, - readableKeysWithMaxTargetSdk); + public static boolean putFloatForUser(ContentResolver cr, String name, float value, + @CanBeCURRENT @UserIdInt int userId) { + return putStringForUser(cr, name, Float.toString(value), userId); } /** - * Look up a name in the database. - * @param resolver to access the database with - * @param name to look up in the table - * @return the corresponding value, or null if not present + * A comma-separated list of package names that should disable hardware overlays while + * they are in the foreground. + * @hide + */ + public static final String DISABLE_HW_OVERLAYS_APPS = "disable_hw_overlays_apps"; + + /** + * Control whether to enable adaptive sleep mode. + * @hide + */ + @Readable + public static final String ADAPTIVE_SLEEP = "adaptive_sleep"; + + /** + * Setting key to indicate whether camera-based autorotate is enabled. + * + * @hide + */ + public static final String CAMERA_AUTOROTATE = "camera_autorotate"; + + /** + * @deprecated Use {@link android.provider.Settings.Global#DEVELOPMENT_SETTINGS_ENABLED} + * instead + */ + @Deprecated + public static final String DEVELOPMENT_SETTINGS_ENABLED = + Global.DEVELOPMENT_SETTINGS_ENABLED; + + /** + * When the user has enable the option to have a "bug report" command + * in the power menu. + * @hide + */ + @Readable + public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu"; + + /** + * The package name for the custom bugreport handler app. This app must be bugreport + * allow-listed. This is currently used only by Power Menu short press. + * @hide + */ + public static final String CUSTOM_BUGREPORT_HANDLER_APP = "custom_bugreport_handler_app"; + + /** + * The user id for the custom bugreport handler app. This is currently used only by Power + * Menu short press. + * @hide + */ + public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user"; + + /** + * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead + */ + @Deprecated + public static final String ADB_ENABLED = Global.ADB_ENABLED; + + /** + * Setting to allow mock locations and location provider status to be injected into the + * LocationManager service for testing purposes during application development. These + * locations and status values override actual location and status information generated + * by network, gps, or other location providers. + * + * @deprecated This settings is not used anymore. + */ + @Deprecated + @Readable + public static final String ALLOW_MOCK_LOCATION = "mock_location"; + + /** + * This is used by Bluetooth Manager to store adapter name + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("NoSettingsProvider") + public static final String BLUETOOTH_NAME = "bluetooth_name"; + + /** + * This is used by Bluetooth Manager to store adapter address + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("NoSettingsProvider") + public static final String BLUETOOTH_ADDRESS = "bluetooth_address"; + + /** + * This is used by Bluetooth Manager to store whether adapter address is valid + * @hide + */ + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("NoSettingsProvider") + public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the broadcast program info. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_PROGRAM_INFO = + "bluetooth_le_broadcast_program_info"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the broadcast name. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_NAME = "bluetooth_le_broadcast_name"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the broadcast code. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_CODE = "bluetooth_le_broadcast_code"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the app source name. + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME = + "bluetooth_le_broadcast_app_source_name"; + + /** + * This is used by LocalBluetoothLeBroadcast to downgrade the broadcast quality to improve + * compatibility. + * + *

    + *
  • 0 = false + *
  • 1 = true + *
+ * + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_IMPROVE_COMPATIBILITY = + "bluetooth_le_broadcast_improve_compatibility"; + + /** + * This is used by LocalBluetoothLeBroadcast to store the fallback active device address. + * + * @hide + */ + public static final String BLUETOOTH_LE_BROADCAST_FALLBACK_ACTIVE_DEVICE_ADDRESS = + "bluetooth_le_broadcast_fallback_active_device_address"; + + /** + * Ringtone routing value for hearing aid. It routes ringtone to hearing aid or device + * speaker. + *
    + *
  • 0 = Default + *
  • 1 = Route to hearing aid + *
  • 2 = Route to device speaker + *
+ * @hide + */ + public static final String HEARING_AID_RINGTONE_ROUTING = + "hearing_aid_ringtone_routing"; + + /** + * Phone call routing value for hearing aid. It routes phone call to hearing aid or + * device speaker. + *
    + *
  • 0 = Default + *
  • 1 = Route to hearing aid + *
  • 2 = Route to device speaker + *
+ * @hide + */ + public static final String HEARING_AID_CALL_ROUTING = + "hearing_aid_call_routing"; + + /** + * Media routing value for hearing aid. It routes media to hearing aid or device + * speaker. + *
    + *
  • 0 = Default + *
  • 1 = Route to hearing aid + *
  • 2 = Route to device speaker + *
+ * @hide + */ + public static final String HEARING_AID_MEDIA_ROUTING = + "hearing_aid_media_routing"; + + /** + * Notification routing value for hearing aid. It routes notification sounds to hearing aid + * or device speaker. + *
    + *
  • 0 = Default + *
  • 1 = Route to hearing aid + *
  • 2 = Route to device speaker + *
+ * @hide + */ + public static final String HEARING_AID_NOTIFICATION_ROUTING = + "hearing_aid_notification_routing"; + + /** + * Setting to indicate that on device captions are enabled. + * + * @hide + */ + @SystemApi + @Readable + public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; + + + /** + * Setting to indicate live caption button show or hide in the volume + * rocker. + * + * @hide */ - public static String getString(ContentResolver resolver, String name) { - return getStringForUser(resolver, name, resolver.getUserId()); - } + public static final String ODI_CAPTIONS_VOLUME_UI_ENABLED = + "odi_captions_volume_ui_enabled"; - /** @hide */ - @UnsupportedAppUsage - public static String getStringForUser(ContentResolver resolver, String name, - @CanBeCURRENT @UserIdInt int userId) { - if (MOVED_TO_GLOBAL.contains(name)) { - Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" - + " to android.provider.Settings.Global."); - return Global.getStringForUser(resolver, name, userId); - } + /** + * On Android 8.0 (API level 26) and higher versions of the platform, + * a 64-bit number (expressed as a hexadecimal string), unique to + * each combination of app-signing key, user, and device. + * Values of {@code ANDROID_ID} are scoped by signing key and user. + * The value may change if a factory reset is performed on the + * device or if an APK signing key changes. + * + * For more information about how the platform handles {@code ANDROID_ID} + * in Android 8.0 (API level 26) and higher, see + * Android 8.0 Behavior Changes. + * + *

Note: For apps that were installed + * prior to updating the device to a version of Android 8.0 + * (API level 26) or higher, the value of {@code ANDROID_ID} changes + * if the app is uninstalled and then reinstalled after the OTA. + * To preserve values across uninstalls after an OTA to Android 8.0 + * or higher, developers can use + * + * Key/Value Backup.

+ * + *

In versions of the platform lower than Android 8.0 (API level 26), + * a 64-bit number (expressed as a hexadecimal string) that is randomly + * generated when the user first sets up the device and should remain + * constant for the lifetime of the user's device. + * + * On devices that have + * + * multiple users, each user appears as a + * completely separate device, so the {@code ANDROID_ID} value is + * unique to each user.

+ * + *

Note: If the caller is an Instant App the ID is scoped + * to the Instant App, it is generated when the Instant App is first installed and reset if + * the user clears the Instant App. + */ + @Readable + public static final String ANDROID_ID = "android_id"; - if (MOVED_TO_LOCK_SETTINGS.contains(name) && Process.myUid() != Process.SYSTEM_UID) { - // No context; use the ActivityThread's context as an approximation for - // determining the target API level. - Application application = ActivityThread.currentApplication(); + /** + * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead + */ + @Deprecated + public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; - boolean isPreMnc = application != null - && application.getApplicationInfo() != null - && application.getApplicationInfo().targetSdkVersion - <= VERSION_CODES.LOLLIPOP_MR1; - if (isPreMnc) { - // Old apps used to get the three deprecated LOCK_PATTERN_* settings from - // ILockSettings.getString(). For security reasons, we now just return a - // stubbed-out value. Note: the only one of these three settings actually known - // to have been used was LOCK_PATTERN_ENABLED, and ILockSettings.getString() - // already always returned "0" for that starting in Android 11. - return "0"; - } - throw new SecurityException("Settings.Secure." + name + " is deprecated and no" + - " longer accessible. See API documentation for potential replacements."); - } + /** + * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead + */ + @Deprecated + public static final String DATA_ROAMING = Global.DATA_ROAMING; - return sNameValueCache.getStringForUser(resolver, name, userId); - } + /** + * Stores {@link android.view.inputmethod.InputMethodInfo#getId()} of the input method + * service that is currently selected. + * + *

Although the name {@link #DEFAULT_INPUT_METHOD} implies that there is a concept of + * default input method, in reality this setting is no more or less than the + * currently selected input method. This setting can be updated at any + * time as a result of user-initiated and system-initiated input method switching.

+ * + *

Use {@link ComponentName#unflattenFromString(String)} to parse the stored value.

+ */ + @Readable + public static final String DEFAULT_INPUT_METHOD = "default_input_method"; /** - * Store a name/value pair into the database. Values written by this method will be - * overridden if a restore happens in the future. + * Used only by {@link com.android.server.inputmethod.InputMethodManagerService} as a + * temporary data store of {@link #DEFAULT_INPUT_METHOD} while a virtual-device-specific + * input method is set as default.

* - * @param resolver to access the database with - * @param name to store - * @param value to associate with the name - * @return true if the value was set, false on database errors + *

This should be considered to be an implementation detail of + * {@link com.android.server.inputmethod.InputMethodManagerService}. Other system + * components should never rely on this value.

* + * @see #DEFAULT_INPUT_METHOD * @hide */ - @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) - public static boolean putString(ContentResolver resolver, String name, - String value, boolean overrideableByRestore) { - return putStringForUser(resolver, name, value, /* tag */ null, /* makeDefault */ false, - resolver.getUserId(), overrideableByRestore); - } + public static final String DEFAULT_DEVICE_INPUT_METHOD = "default_device_input_method"; /** - * Store a name/value pair into the database. - * @param resolver to access the database with - * @param name to store - * @param value to associate with the name - * @return true if the value was set, false on database errors + * Setting to record the input method subtype used by default, holding the ID + * of the desired method. */ - public static boolean putString(ContentResolver resolver, String name, String value) { - return putStringForUser(resolver, name, value, resolver.getUserId()); - } + @Readable + public static final String SELECTED_INPUT_METHOD_SUBTYPE = + "selected_input_method_subtype"; - /** @hide */ - @UnsupportedAppUsage - public static boolean putStringForUser(ContentResolver resolver, String name, String value, - @CanBeCURRENT @UserIdInt int userId) { - return putStringForUser(resolver, name, value, null, false, userId, - DEFAULT_OVERRIDEABLE_BY_RESTORE); - } + /** + * The {@link android.view.inputmethod.InputMethodInfo.InputMethodInfo#getId() ID} of the + * default voice input method. + *

+ * This stores the last known default voice IME. If the related system config value changes, + * this is reset by InputMethodManagerService. + *

+ * This IME is not necessarily in the enabled IME list. That state is still stored in + * {@link #ENABLED_INPUT_METHODS}. + * + * @hide + */ + public static final String DEFAULT_VOICE_INPUT_METHOD = "default_voice_input_method"; - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean putStringForUser(@NonNull ContentResolver resolver, - @NonNull String name, @Nullable String value, @Nullable String tag, - boolean makeDefault, @CanBeCURRENT @UserIdInt int userId, - boolean overrideableByRestore) { - if (LOCAL_LOGV) { - Log.v(TAG, "Secure.putString(name=" + name + ", value=" + value + ") for " - + userId); - } - if (MOVED_TO_GLOBAL.contains(name)) { - Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" - + " to android.provider.Settings.Global"); - return Global.putStringForUser(resolver, name, value, - tag, makeDefault, userId, DEFAULT_OVERRIDEABLE_BY_RESTORE); - } - return sNameValueCache.putStringForUser(resolver, name, value, tag, - makeDefault, userId, overrideableByRestore); - } + /** + * Setting to record the history of input method subtype, holding the pair of ID of IME + * and its last used subtype. + * @hide + */ + @Readable + public static final String INPUT_METHODS_SUBTYPE_HISTORY = + "input_methods_subtype_history"; /** - * Store a name/value pair into the database. - *

- * The method takes an optional tag to associate with the setting - * which can be used to clear only settings made by your package and - * associated with this tag by passing the tag to {@link - * #resetToDefaults(ContentResolver, String)}. Anyone can override - * the current tag. Also if another package changes the setting - * then the tag will be set to the one specified in the set call - * which can be null. Also any of the settings setters that do not - * take a tag as an argument effectively clears the tag. - *

- * For example, if you set settings A and B with tags T1 and T2 and - * another app changes setting A (potentially to the same value), it - * can assign to it a tag T3 (note that now the package that changed - * the setting is not yours). Now if you reset your changes for T1 and - * T2 only setting B will be reset and A not (as it was changed by - * another package) but since A did not change you are in the desired - * initial state. Now if the other app changes the value of A (assuming - * you registered an observer in the beginning) you would detect that - * the setting was changed by another app and handle this appropriately - * (ignore, set back to some value, etc). - *

- * Also the method takes an argument whether to make the value the - * default for this setting. If the system already specified a default - * value, then the one passed in here will not - * be set as the default. - *

+ * Setting to record the visibility of input method selector + */ + @Readable + public static final String INPUT_METHOD_SELECTOR_VISIBILITY = + "input_method_selector_visibility"; + + /** + * Toggle for enabling stylus handwriting. When enabled, current Input method receives + * stylus {@link MotionEvent}s if an {@link Editor} is focused. * - * @param resolver to access the database with. - * @param name to store. - * @param value to associate with the name. - * @param tag to associate with the setting. - * @param makeDefault whether to make the value the default one. - * @return true if the value was set, false on database errors. + * @see #STYLUS_HANDWRITING_DEFAULT_VALUE + * @hide + */ + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; + + /** + * Default value for {@link #STYLUS_HANDWRITING_ENABLED}. * - * @see #resetToDefaults(ContentResolver, String) + * @hide + */ + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final int STYLUS_HANDWRITING_DEFAULT_VALUE = 1; + + /** + * The currently selected voice interaction service flattened ComponentName. + * @hide + */ + @TestApi + @Readable + public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; + + + /** + * The currently selected credential service(s) flattened ComponentName. * * @hide */ - @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - public static boolean putString(@NonNull ContentResolver resolver, - @NonNull String name, @Nullable String value, @Nullable String tag, - boolean makeDefault) { - return putStringForUser(resolver, name, value, tag, makeDefault, - resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE); - } + public static final String CREDENTIAL_SERVICE = "credential_service"; /** - * Reset the settings to their defaults. This would reset only - * settings set by the caller's package. Think of it of a way to undo your own - * changes to the global settings. Passing in the optional tag will reset only - * settings changed by your package and associated with this tag. + * The currently selected primary credential service flattened ComponentName. * - * @param resolver Handle to the content resolver. - * @param tag Optional tag which should be associated with the settings to reset. + * @hide + */ + public static final String CREDENTIAL_SERVICE_PRIMARY = "credential_service_primary"; + + /** + * The currently selected autofill service flattened ComponentName. + * @hide + */ + @TestApi + @Readable + public static final String AUTOFILL_SERVICE = "autofill_service"; + + /** + * Boolean indicating if Autofill supports field classification. * - * @see #putString(ContentResolver, String, String, String, boolean) + * @see android.service.autofill.AutofillService * * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - public static void resetToDefaults(@NonNull ContentResolver resolver, - @Nullable String tag) { - resetToDefaultsAsUser(resolver, tag, RESET_MODE_PACKAGE_DEFAULTS, - resolver.getUserId()); - } + @Readable + public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = + "autofill_field_classification"; /** - * - * Reset the settings to their defaults for a given user with a specific mode. The - * optional tag argument is valid only for {@link #RESET_MODE_PACKAGE_DEFAULTS} - * allowing resetting the settings made by a package and associated with the tag. - * - * @param resolver Handle to the content resolver. - * @param tag Optional tag which should be associated with the settings to reset. - * @param mode The reset mode. - * @param userId The user for which to reset to defaults. - * - * @see #RESET_MODE_PACKAGE_DEFAULTS - * @see #RESET_MODE_UNTRUSTED_DEFAULTS - * @see #RESET_MODE_UNTRUSTED_CHANGES - * @see #RESET_MODE_TRUSTED_DEFAULTS + * Boolean indicating if the dark mode dialog shown on first toggle has been seen. * * @hide */ - public static void resetToDefaultsAsUser(@NonNull ContentResolver resolver, - @Nullable String tag, @ResetMode int mode, - @IntRange(from = 0) @CannotBeSpecialUser @UserIdInt int userId) { - try { - Bundle arg = new Bundle(); - arg.putInt(CALL_METHOD_USER_KEY, userId); - if (tag != null) { - arg.putString(CALL_METHOD_TAG_KEY, tag); - } - arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode); - IContentProvider cp = sProviderHolder.getProvider(resolver); - if (cp == null) { - Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI - + " because cp is null"); - return; - } - cp.call(resolver.getAttributionSource(), - sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg); - } catch (RemoteException e) { - Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e); - } - } + @Readable + public static final String DARK_MODE_DIALOG_SEEN = + "dark_mode_dialog_seen"; /** - * Construct the content URI for a particular name/value pair, - * useful for monitoring changes with a ContentObserver. - * @param name to look up in the table - * @return the corresponding content URI, or null if not present + * Custom time when Dark theme is scheduled to activate. + * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). + * @hide */ - public static Uri getUriFor(String name) { - if (MOVED_TO_GLOBAL.contains(name)) { - Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure" - + " to android.provider.Settings.Global, returning global URI."); - return Global.getUriFor(Global.CONTENT_URI, name); - } - return getUriFor(CONTENT_URI, name); - } + @Readable + public static final String DARK_THEME_CUSTOM_START_TIME = + "dark_theme_custom_start_time"; /** - * Convenience function for retrieving a single secure settings value - * as an integer. Note that internally setting values are always - * stored as strings; this function converts the string to an integer - * for you. The default value will be returned if the setting is - * not defined or not an integer. - * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. - * @param def Value to return if the setting is not defined. - * - * @return The setting's current value, or 'def' if it is not defined - * or not a valid integer. + * Custom time when Dark theme is scheduled to deactivate. + * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). + * @hide */ - public static int getInt(ContentResolver cr, String name, int def) { - return getIntForUser(cr, name, def, cr.getUserId()); - } + @Readable + public static final String DARK_THEME_CUSTOM_END_TIME = + "dark_theme_custom_end_time"; - /** @hide */ - @UnsupportedAppUsage - public static int getIntForUser(ContentResolver cr, String name, int def, - @CanBeCURRENT @UserIdInt int userId) { - String v = getStringForUser(cr, name, userId); - return parseIntSettingWithDefault(v, def); - } + /** + * Defines value returned by {@link android.service.autofill.UserData#getMaxUserDataSize()}. + * + * @hide + */ + @SystemApi + @Readable + public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = + "autofill_user_data_max_user_data_size"; /** - * Convenience function for retrieving a single secure settings value - * as an integer. Note that internally setting values are always - * stored as strings; this function converts the string to an integer - * for you. - *

- * This version does not take a default value. If the setting has not - * been set, or the string value is not a number, - * it throws {@link SettingNotFoundException}. + * Defines value returned by + * {@link android.service.autofill.UserData#getMaxFieldClassificationIdsSize()}. * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. + * @hide + */ + @SystemApi + @Readable + public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = + "autofill_user_data_max_field_classification_size"; + + /** + * Defines value returned by + * {@link android.service.autofill.UserData#getMaxCategoryCount()}. * - * @throws SettingNotFoundException Thrown if a setting by the given - * name can't be found or the setting value is not an integer. + * @hide + */ + @SystemApi + @Readable + public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = + "autofill_user_data_max_category_count"; + + /** + * Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}. * - * @return The setting's current value. + * @hide */ - public static int getInt(ContentResolver cr, String name) - throws SettingNotFoundException { - return getIntForUser(cr, name, cr.getUserId()); - } + @SystemApi + @Readable + public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = + "autofill_user_data_max_value_length"; - /** @hide */ - public static int getIntForUser(ContentResolver cr, String name, - @CanBeCURRENT @UserIdInt int userId) - throws SettingNotFoundException { - String v = getStringForUser(cr, name, userId); - return parseIntSetting(v, name); - } + /** + * Defines value returned by {@link android.service.autofill.UserData#getMinValueLength()}. + * + * @hide + */ + @SystemApi + @Readable + public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = + "autofill_user_data_min_value_length"; /** - * Convenience function for updating a single settings value as an - * integer. This will either create a new entry in the table if the - * given name does not exist, or modify the value of the existing row - * with that name. Note that internally setting values are always - * stored as strings, so this function converts the given value to a - * string before storing it. + * Defines whether Content Capture is enabled for the user. * - * @param cr The ContentResolver to access. - * @param name The name of the setting to modify. - * @param value The new value for the setting. - * @return true if the value was set, false on database errors + *

Type: {@code int} ({@code 0} for disabled, {@code 1} for enabled). + *

Default: enabled + * + * @hide */ - public static boolean putInt(ContentResolver cr, String name, int value) { - return putIntForUser(cr, name, value, cr.getUserId()); - } + @TestApi + @Readable + public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled"; - /** @hide */ - @UnsupportedAppUsage - public static boolean putIntForUser(ContentResolver cr, String name, int value, - @CanBeCURRENT @UserIdInt int userId) { - return putStringForUser(cr, name, Integer.toString(value), userId); - } + /** + * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead + */ + @Deprecated + public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; /** - * Convenience function for retrieving a single secure settings value - * as a {@code long}. Note that internally setting values are always - * stored as strings; this function converts the string to a {@code long} - * for you. The default value will be returned if the setting is - * not defined or not a {@code long}. + * Indicates whether a DPC has been downloaded during provisioning. * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. - * @param def Value to return if the setting is not defined. + *

Type: int (0 for false, 1 for true) * - * @return The setting's current value, or 'def' if it is not defined - * or not a valid {@code long}. + *

If this is true, then any attempts to begin setup again should result in factory reset + * + * @hide */ - public static long getLong(ContentResolver cr, String name, long def) { - return getLongForUser(cr, name, def, cr.getUserId()); - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static long getLongForUser(ContentResolver cr, String name, long def, - @CanBeCURRENT @UserIdInt int userId) { - String v = getStringForUser(cr, name, userId); - return parseLongSettingWithDefault(v, def); - } + @Readable + public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED = + "managed_provisioning_dpc_downloaded"; /** - * Convenience function for retrieving a single secure settings value - * as a {@code long}. Note that internally setting values are always - * stored as strings; this function converts the string to a {@code long} - * for you. + * Indicates whether the device is under restricted secure FRP mode. + * Secure FRP mode is enabled when the device is under FRP. On solving of FRP challenge, + * device is removed from this mode. *

- * This version does not take a default value. If the setting has not - * been set, or the string value is not a number, - * it throws {@link SettingNotFoundException}. - * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. + * Type: int (0 for false, 1 for true) * - * @return The setting's current value. - * @throws SettingNotFoundException Thrown if a setting by the given - * name can't be found or the setting value is not an integer. + * @deprecated Use Global.SECURE_FRP_MODE */ - public static long getLong(ContentResolver cr, String name) - throws SettingNotFoundException { - return getLongForUser(cr, name, cr.getUserId()); - } - - /** @hide */ - public static long getLongForUser(ContentResolver cr, String name, - @CanBeCURRENT @UserIdInt int userId) - throws SettingNotFoundException { - String v = getStringForUser(cr, name, userId); - return parseLongSetting(v, name); - } + @Deprecated + @Readable + public static final String SECURE_FRP_MODE = "secure_frp_mode"; /** - * Convenience function for updating a secure settings value as a long - * integer. This will either create a new entry in the table if the - * given name does not exist, or modify the value of the existing row - * with that name. Note that internally setting values are always - * stored as strings, so this function converts the given value to a - * string before storing it. + * Indicates whether the current user has completed setup via the setup wizard. + *

+ * Type: int (0 for false, 1 for true) * - * @param cr The ContentResolver to access. - * @param name The name of the setting to modify. - * @param value The new value for the setting. - * @return true if the value was set, false on database errors + * @hide */ - public static boolean putLong(ContentResolver cr, String name, long value) { - return putLongForUser(cr, name, value, cr.getUserId()); - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean putLongForUser(ContentResolver cr, String name, long value, - @CanBeCURRENT @UserIdInt int userId) { - return putStringForUser(cr, name, Long.toString(value), userId); - } + @SystemApi + @Readable + public static final String USER_SETUP_COMPLETE = "user_setup_complete"; /** - * Convenience function for retrieving a single secure settings value - * as a floating point number. Note that internally setting values are - * always stored as strings; this function converts the string to an - * float for you. The default value will be returned if the setting - * is not defined or not a valid float. - * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. - * @param def Value to return if the setting is not defined. + * Indicates that the user has not started setup personalization. + * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. * - * @return The setting's current value, or 'def' if it is not defined - * or not a valid float. + * @hide */ - public static float getFloat(ContentResolver cr, String name, float def) { - return getFloatForUser(cr, name, def, cr.getUserId()); - } - - /** @hide */ - public static float getFloatForUser(ContentResolver cr, String name, float def, - @CanBeCURRENT @UserIdInt int userId) { - String v = getStringForUser(cr, name, userId); - return parseFloatSettingWithDefault(v, def); - } + @SystemApi + public static final int USER_SETUP_PERSONALIZATION_NOT_STARTED = 0; /** - * Convenience function for retrieving a single secure settings value - * as a float. Note that internally setting values are always - * stored as strings; this function converts the string to a float - * for you. - *

- * This version does not take a default value. If the setting has not - * been set, or the string value is not a number, - * it throws {@link SettingNotFoundException}. + * Indicates that the user has not yet completed setup personalization. + * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. * - * @param cr The ContentResolver to access. - * @param name The name of the setting to retrieve. + * @hide + */ + @SystemApi + public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; + + /** + * Indicates that the user has snoozed personalization and will complete it later. + * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. * - * @throws SettingNotFoundException Thrown if a setting by the given - * name can't be found or the setting value is not a float. + * @hide + */ + @SystemApi + public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2; + + /** + * Indicates that the user has completed setup personalization. + * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. * - * @return The setting's current value. + * @hide */ - public static float getFloat(ContentResolver cr, String name) - throws SettingNotFoundException { - return getFloatForUser(cr, name, cr.getUserId()); - } + @SystemApi + public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; /** @hide */ - public static float getFloatForUser(ContentResolver cr, String name, - @CanBeCURRENT @UserIdInt int userId) - throws SettingNotFoundException { - String v = getStringForUser(cr, name, userId); - return parseFloatSetting(v, name); - } + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + USER_SETUP_PERSONALIZATION_NOT_STARTED, + USER_SETUP_PERSONALIZATION_STARTED, + USER_SETUP_PERSONALIZATION_PAUSED, + USER_SETUP_PERSONALIZATION_COMPLETE + }) + public @interface UserSetupPersonalization {} /** - * Convenience function for updating a single settings value as a - * floating point number. This will either create a new entry in the - * table if the given name does not exist, or modify the value of the - * existing row with that name. Note that internally setting values - * are always stored as strings, so this function converts the given - * value to a string before storing it. + * Defines the user's current state of device personalization. + * The possible states are defined in {@link UserSetupPersonalization}. * - * @param cr The ContentResolver to access. - * @param name The name of the setting to modify. - * @param value The new value for the setting. - * @return true if the value was set, false on database errors + * @hide */ - public static boolean putFloat(ContentResolver cr, String name, float value) { - return putFloatForUser(cr, name, value, cr.getUserId()); - } + @SystemApi + @Readable + public static final String USER_SETUP_PERSONALIZATION_STATE = + "user_setup_personalization_state"; - /** @hide */ - public static boolean putFloatForUser(ContentResolver cr, String name, float value, - @CanBeCURRENT @UserIdInt int userId) { - return putStringForUser(cr, name, Float.toString(value), userId); - } + /** + * Whether the current user has been set up via setup wizard (0 = false, 1 = true) + * This value differs from USER_SETUP_COMPLETE in that it can be reset back to 0 + * in case SetupWizard has been re-enabled on TV devices. + * + * @hide + */ + @Readable + public static final String TV_USER_SETUP_COMPLETE = "tv_user_setup_complete"; /** - * Control whether to enable adaptive sleep mode. + * The prefix for a category name that indicates whether a suggested action from that + * category was marked as completed. + *

+ * Type: int (0 for false, 1 for true) + * * @hide */ + @SystemApi @Readable - public static final String ADAPTIVE_SLEEP = "adaptive_sleep"; + public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category."; /** - * Setting key to indicate whether camera-based autorotate is enabled. + * Whether or not compress blocks should be released on install. + *

The setting only determines if the platform will attempt to release + * compress blocks; it does not guarantee that the files will have their + * compress blocks released. Compression is currently only supported on + * some f2fs filesystems. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - public static final String CAMERA_AUTOROTATE = "camera_autorotate"; + public static final String RELEASE_COMPRESS_BLOCKS_ON_INSTALL = + "release_compress_blocks_on_install"; /** - * @deprecated Use {@link android.provider.Settings.Global#DEVELOPMENT_SETTINGS_ENABLED} - * instead + * List of input methods that are currently enabled. This is a string + * containing the IDs of all enabled input methods, each ID separated + * by ':'. + * + * Format like "ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0" + * where imeId is ComponentName and subtype is int32. + * + *

Note: This setting is not readable to the app targeting API level 34 or higher. use + * {@link android.view.inputmethod.InputMethodManager#getEnabledInputMethodList()} instead. */ - @Deprecated - public static final String DEVELOPMENT_SETTINGS_ENABLED = - Global.DEVELOPMENT_SETTINGS_ENABLED; + @Readable(maxTargetSdk = Build.VERSION_CODES.TIRAMISU) + public static final String ENABLED_INPUT_METHODS = "enabled_input_methods"; /** - * When the user has enable the option to have a "bug report" command - * in the power menu. + * List of system input methods that are currently disabled. This is a string + * containing the IDs of all disabled input methods, each ID separated + * by ':'. * @hide */ - @Readable - public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu"; + @Readable(maxTargetSdk = Build.VERSION_CODES.TIRAMISU) + public static final String DISABLED_SYSTEM_INPUT_METHODS = "disabled_system_input_methods"; /** - * The package name for the custom bugreport handler app. This app must be bugreport - * allow-listed. This is currently used only by Power Menu short press. + * Whether to show the IME when a hard keyboard is connected. This is a boolean that + * determines if the IME should be shown when a hard keyboard is attached. * @hide */ - public static final String CUSTOM_BUGREPORT_HANDLER_APP = "custom_bugreport_handler_app"; + @TestApi + @Readable + @SuppressLint("NoSettingsProvider") + public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard"; /** - * The user id for the custom bugreport handler app. This is currently used only by Power - * Menu short press. + * Whether to enable bounce keys for Physical Keyboard accessibility. + * + * If set to non-zero value, any key press on physical keyboard within the provided + * threshold duration (in milliseconds) of the same key, will be ignored. + * * @hide */ - public static final String CUSTOM_BUGREPORT_HANDLER_USER = "custom_bugreport_handler_user"; + @Readable + public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys"; /** - * @deprecated Use {@link android.provider.Settings.Global#ADB_ENABLED} instead + * Whether to enable slow keys for Physical Keyboard accessibility. + * + * If set to non-zero value, any key press on physical keyboard needs to be pressed and + * held for the provided threshold duration (in milliseconds) to be registered in the + * system. + * + * @hide */ - @Deprecated - public static final String ADB_ENABLED = Global.ADB_ENABLED; + @Readable + public static final String ACCESSIBILITY_SLOW_KEYS = "accessibility_slow_keys"; /** - * Setting to allow mock locations and location provider status to be injected into the - * LocationManager service for testing purposes during application development. These - * locations and status values override actual location and status information generated - * by network, gps, or other location providers. + * Whether to enable sticky keys for Physical Keyboard accessibility. * - * @deprecated This settings is not used anymore. + * This is a boolean value that determines if Sticky keys feature is enabled. + * + * @hide */ - @Deprecated @Readable - public static final String ALLOW_MOCK_LOCATION = "mock_location"; + public static final String ACCESSIBILITY_STICKY_KEYS = "accessibility_sticky_keys"; /** - * This is used by Bluetooth Manager to store adapter name + * Whether stylus button presses are disabled. This is a boolean that + * determines if stylus buttons are ignored. + * * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.S) - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @TestApi + @Readable @SuppressLint("NoSettingsProvider") - public static final String BLUETOOTH_NAME = "bluetooth_name"; + public static final String STYLUS_BUTTONS_ENABLED = "stylus_buttons_enabled"; /** - * This is used by Bluetooth Manager to store adapter address + * Preferred default user profile to use with the notes task button shortcut. + * * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.S) - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SuppressLint("NoSettingsProvider") - public static final String BLUETOOTH_ADDRESS = "bluetooth_address"; + public static final String DEFAULT_NOTE_TASK_PROFILE = "default_note_task_profile"; /** - * This is used by Bluetooth Manager to store whether adapter address is valid - * @hide + * Host name and port for global http proxy. Uses ':' seperator for + * between host and port. + * + * @deprecated Use {@link Global#HTTP_PROXY} */ - @Readable(maxTargetSdk = Build.VERSION_CODES.S) - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - @SuppressLint("NoSettingsProvider") - public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid"; + @Deprecated + public static final String HTTP_PROXY = Global.HTTP_PROXY; /** - * This is used by LocalBluetoothLeBroadcast to store the broadcast program info. + * Package designated as always-on VPN provider. + * * @hide */ - public static final String BLUETOOTH_LE_BROADCAST_PROGRAM_INFO = - "bluetooth_le_broadcast_program_info"; + public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app"; /** - * This is used by LocalBluetoothLeBroadcast to store the broadcast name. + * Whether to block networking outside of VPN connections while always-on is set. + * @see #ALWAYS_ON_VPN_APP + * * @hide */ - public static final String BLUETOOTH_LE_BROADCAST_NAME = "bluetooth_le_broadcast_name"; + @Readable + public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown"; /** - * This is used by LocalBluetoothLeBroadcast to store the broadcast code. + * Comma separated list of packages that are allowed to access the network when VPN is in + * lockdown mode but not running. + * @see #ALWAYS_ON_VPN_LOCKDOWN + * * @hide */ - public static final String BLUETOOTH_LE_BROADCAST_CODE = "bluetooth_le_broadcast_code"; + @Readable(maxTargetSdk = Build.VERSION_CODES.S) + public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST = + "always_on_vpn_lockdown_whitelist"; /** - * This is used by LocalBluetoothLeBroadcast to store the app source name. - * @hide + * Whether applications can be installed for this user via the system's + * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism. + * + *

1 = permit app installation via the system package installer intent + *

0 = do not allow use of the package installer + * @deprecated Starting from {@link android.os.Build.VERSION_CODES#O}, apps should use + * {@link PackageManager#canRequestPackageInstalls()} + * @see PackageManager#canRequestPackageInstalls() */ - public static final String BLUETOOTH_LE_BROADCAST_APP_SOURCE_NAME = - "bluetooth_le_broadcast_app_source_name"; + @Deprecated + @Readable + public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; /** - * This is used by LocalBluetoothLeBroadcast to downgrade the broadcast quality to improve - * compatibility. - * - *

    - *
  • 0 = false - *
  • 1 = true - *
+ * A flag to tell {@link com.android.server.devicepolicy.DevicePolicyManagerService} that + * the default for {@link #INSTALL_NON_MARKET_APPS} is reversed for this user on OTA. So it + * can set the restriction {@link android.os.UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} + * on behalf of the profile owner if needed to make the change transparent for profile + * owners. * * @hide */ - public static final String BLUETOOTH_LE_BROADCAST_IMPROVE_COMPATIBILITY = - "bluetooth_le_broadcast_improve_compatibility"; + @Readable + public static final String UNKNOWN_SOURCES_DEFAULT_REVERSED = + "unknown_sources_default_reversed"; /** - * This is used by LocalBluetoothLeBroadcast to store the fallback active device address. + * Comma-separated list of location providers that are enabled. Do not rely on this value + * being present or correct, or on ContentObserver notifications on the corresponding Uri. * - * @hide + * @deprecated This setting no longer exists from Android S onwards as it no longer is + * capable of realistically reflecting location settings. Use {@link + * LocationManager#isProviderEnabled(String)} or {@link LocationManager#isLocationEnabled()} + * instead. */ - public static final String BLUETOOTH_LE_BROADCAST_FALLBACK_ACTIVE_DEVICE_ADDRESS = - "bluetooth_le_broadcast_fallback_active_device_address"; + @Deprecated + @Readable + public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; /** - * Ringtone routing value for hearing aid. It routes ringtone to hearing aid or device - * speaker. - *
    - *
  • 0 = Default - *
  • 1 = Route to hearing aid - *
  • 2 = Route to device speaker - *
- * @hide + * The current location mode of the device. Do not rely on this value being present or on + * ContentObserver notifications on the corresponding Uri. + * + * @deprecated The preferred methods for checking location mode and listening for changes + * are via {@link LocationManager#isLocationEnabled()} and + * {@link LocationManager#MODE_CHANGED_ACTION}. */ - public static final String HEARING_AID_RINGTONE_ROUTING = - "hearing_aid_ringtone_routing"; + @Deprecated + @Readable + public static final String LOCATION_MODE = "location_mode"; /** - * Phone call routing value for hearing aid. It routes phone call to hearing aid or - * device speaker. - *
    - *
  • 0 = Default - *
  • 1 = Route to hearing aid - *
  • 2 = Route to device speaker - *
+ * The App or module that changes the location mode. * @hide */ - public static final String HEARING_AID_CALL_ROUTING = - "hearing_aid_call_routing"; + @Readable + public static final String LOCATION_CHANGER = "location_changer"; /** - * Media routing value for hearing aid. It routes media to hearing aid or device - * speaker. - *
    - *
  • 0 = Default - *
  • 1 = Route to hearing aid - *
  • 2 = Route to device speaker - *
+ * The location changer is unknown or unable to detect. * @hide */ - public static final String HEARING_AID_MEDIA_ROUTING = - "hearing_aid_media_routing"; + public static final int LOCATION_CHANGER_UNKNOWN = 0; /** - * Notification routing value for hearing aid. It routes notification sounds to hearing aid - * or device speaker. - *
    - *
  • 0 = Default - *
  • 1 = Route to hearing aid - *
  • 2 = Route to device speaker - *
+ * Location settings in system settings. * @hide */ - public static final String HEARING_AID_NOTIFICATION_ROUTING = - "hearing_aid_notification_routing"; + public static final int LOCATION_CHANGER_SYSTEM_SETTINGS = 1; /** - * Setting to indicate that on device captions are enabled. - * + * The location icon in drop down notification drawer. * @hide */ - @SystemApi - @Readable - public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; - + public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2; /** - * Setting to indicate live caption button show or hide in the volume - * rocker. - * - * @hide + * Location mode is off. */ - public static final String ODI_CAPTIONS_VOLUME_UI_ENABLED = - "odi_captions_volume_ui_enabled"; + public static final int LOCATION_MODE_OFF = 0; /** - * On Android 8.0 (API level 26) and higher versions of the platform, - * a 64-bit number (expressed as a hexadecimal string), unique to - * each combination of app-signing key, user, and device. - * Values of {@code ANDROID_ID} are scoped by signing key and user. - * The value may change if a factory reset is performed on the - * device or if an APK signing key changes. - * - * For more information about how the platform handles {@code ANDROID_ID} - * in Android 8.0 (API level 26) and higher, see - * Android 8.0 Behavior Changes. - * - *

Note: For apps that were installed - * prior to updating the device to a version of Android 8.0 - * (API level 26) or higher, the value of {@code ANDROID_ID} changes - * if the app is uninstalled and then reinstalled after the OTA. - * To preserve values across uninstalls after an OTA to Android 8.0 - * or higher, developers can use - * - * Key/Value Backup.

- * - *

In versions of the platform lower than Android 8.0 (API level 26), - * a 64-bit number (expressed as a hexadecimal string) that is randomly - * generated when the user first sets up the device and should remain - * constant for the lifetime of the user's device. - * - * On devices that have - * - * multiple users, each user appears as a - * completely separate device, so the {@code ANDROID_ID} value is - * unique to each user.

+ * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. * - *

Note: If the caller is an Instant App the ID is scoped - * to the Instant App, it is generated when the Instant App is first installed and reset if - * the user clears the Instant App. + * @deprecated See {@link #LOCATION_MODE}. */ - @Readable - public static final String ANDROID_ID = "android_id"; + @Deprecated + public static final int LOCATION_MODE_SENSORS_ONLY = 1; /** - * @deprecated Use {@link android.provider.Settings.Global#BLUETOOTH_ON} instead + * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. + * + * @deprecated See {@link #LOCATION_MODE}. */ @Deprecated - public static final String BLUETOOTH_ON = Global.BLUETOOTH_ON; + public static final int LOCATION_MODE_BATTERY_SAVING = 2; /** - * @deprecated Use {@link android.provider.Settings.Global#DATA_ROAMING} instead + * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. + * + * @deprecated See {@link #LOCATION_MODE}. */ @Deprecated - public static final String DATA_ROAMING = Global.DATA_ROAMING; + public static final int LOCATION_MODE_HIGH_ACCURACY = 3; /** - * Stores {@link android.view.inputmethod.InputMethodInfo#getId()} of the input method - * service that is currently selected. - * - *

Although the name {@link #DEFAULT_INPUT_METHOD} implies that there is a concept of - * default input method, in reality this setting is no more or less than the - * currently selected input method. This setting can be updated at any - * time as a result of user-initiated and system-initiated input method switching.

+ * Location mode is on. * - *

Use {@link ComponentName#unflattenFromString(String)} to parse the stored value.

+ * @hide */ - @Readable - public static final String DEFAULT_INPUT_METHOD = "default_input_method"; + @SystemApi + public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY; /** - * Used only by {@link com.android.server.inputmethod.InputMethodManagerService} as a - * temporary data store of {@link #DEFAULT_INPUT_METHOD} while a virtual-device-specific - * input method is set as default.

+ * The current location time zone detection enabled state for the user. * - *

This should be considered to be an implementation detail of - * {@link com.android.server.inputmethod.InputMethodManagerService}. Other system - * components should never rely on this value.

+ * See {@link android.app.time.TimeManager#getTimeZoneCapabilitiesAndConfig} for access. + * See {@link android.app.time.TimeManager#updateTimeZoneConfiguration} to update. + * @hide + */ + public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED = + "location_time_zone_detection_enabled"; + + /** + * The accuracy in meters used for coarsening location for clients with only the coarse + * location permission. * - * @see #DEFAULT_INPUT_METHOD * @hide */ - public static final String DEFAULT_DEVICE_INPUT_METHOD = "default_device_input_method"; + @Readable + public static final String LOCATION_COARSE_ACCURACY_M = "locationCoarseAccuracy"; /** - * Setting to record the input method subtype used by default, holding the ID - * of the desired method. + * Whether or not to show display system location accesses. + * @hide */ - @Readable - public static final String SELECTED_INPUT_METHOD_SUBTYPE = - "selected_input_method_subtype"; + public static final String LOCATION_SHOW_SYSTEM_OPS = "locationShowSystemOps"; /** - * The {@link android.view.inputmethod.InputMethodInfo.InputMethodInfo#getId() ID} of the - * default voice input method. - *

- * This stores the last known default voice IME. If the related system config value changes, - * this is reset by InputMethodManagerService. - *

- * This IME is not necessarily in the enabled IME list. That state is still stored in - * {@link #ENABLED_INPUT_METHODS}. - * + * A flag containing settings used for biometric weak * @hide */ - public static final String DEFAULT_VOICE_INPUT_METHOD = "default_voice_input_method"; + @Deprecated + @Readable + public static final String LOCK_BIOMETRIC_WEAK_FLAGS = + "lock_biometric_weak_flags"; /** - * Setting to record the history of input method subtype, holding the pair of ID of IME - * and its last used subtype. + * Whether lock-to-app will lock the keyguard when exiting. * @hide */ @Readable - public static final String INPUT_METHODS_SUBTYPE_HISTORY = - "input_methods_subtype_history"; + public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked"; /** - * Setting to record the visibility of input method selector + * Whether autolock is enabled (0 = false, 1 = true) + * + * @deprecated Use {@link android.app.KeyguardManager} to determine the state and security + * level of the keyguard. Accessing this setting from an app that is targeting + * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. */ + @Deprecated @Readable - public static final String INPUT_METHOD_SELECTOR_VISIBILITY = - "input_method_selector_visibility"; + public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; /** - * Toggle for enabling stylus handwriting. When enabled, current Input method receives - * stylus {@link MotionEvent}s if an {@link Editor} is focused. + * Whether lock pattern is visible as user enters (0 = false, 1 = true) * - * @see #STYLUS_HANDWRITING_DEFAULT_VALUE - * @hide + * @deprecated Accessing this setting from an app that is targeting + * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. */ - @TestApi + @Deprecated @Readable - @SuppressLint("NoSettingsProvider") - public static final String STYLUS_HANDWRITING_ENABLED = "stylus_handwriting_enabled"; + public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"; /** - * Default value for {@link #STYLUS_HANDWRITING_ENABLED}. + * Whether lock pattern will vibrate as user enters (0 = false, 1 = + * true) * - * @hide + * @deprecated Starting in {@link VERSION_CODES#JELLY_BEAN_MR1} the + * lockscreen uses + * {@link Settings.System#HAPTIC_FEEDBACK_ENABLED}. + * Accessing this setting from an app that is targeting + * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. */ - @TestApi + @Deprecated @Readable - @SuppressLint("NoSettingsProvider") - public static final int STYLUS_HANDWRITING_DEFAULT_VALUE = 1; + public static final String + LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled"; /** - * The currently selected voice interaction service flattened ComponentName. + * Determines the width and height of the LockPatternView widget * @hide */ - @TestApi - @Readable - public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; + public static final String LOCK_PATTERN_SIZE = "lock_pattern_size"; + /** + * Whether lock pattern will show dots (0 = false, 1 = true) + * @hide + */ + public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible"; /** - * The currently selected credential service(s) flattened ComponentName. - * + * Whether lockscreen error pattern is visible (0 = false, 1 = true) * @hide */ - public static final String CREDENTIAL_SERVICE = "credential_service"; + public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path"; /** - * The currently selected primary credential service flattened ComponentName. - * + * This preference allows the device to be locked given time after screen goes off, + * subject to current DeviceAdmin policy limits. * @hide */ - public static final String CREDENTIAL_SERVICE_PRIMARY = "credential_service_primary"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Readable + public static final String LOCK_SCREEN_LOCK_AFTER_TIMEOUT = "lock_screen_lock_after_timeout"; /** - * The currently selected autofill service flattened ComponentName. + * Whether to show the charging info on the lockscreen while charging * @hide */ - @TestApi + public static final String LOCKSCREEN_BATTERY_INFO = "lockscreen_charging_info"; + + /** + * Whether to show the detailed charging info on the lockscreen while charging + * @hide + */ + public static final String LOCKSCREEN_CHARGING_INFO_DETAILS = "lockscreen_charging_info_details"; + + /** + * This preference contains the string that shows for owner info on LockScreen. + * @hide + * @deprecated + */ + @Deprecated @Readable - public static final String AUTOFILL_SERVICE = "autofill_service"; + public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info"; /** - * Boolean indicating if Autofill supports field classification. - * - * @see android.service.autofill.AutofillService - * + * Ids of the user-selected appwidgets on the lockscreen (comma-delimited). * @hide */ - @SystemApi + @Deprecated @Readable - public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = - "autofill_field_classification"; + public static final String LOCK_SCREEN_APPWIDGET_IDS = + "lock_screen_appwidget_ids"; /** - * Boolean indicating if the dark mode dialog shown on first toggle has been seen. - * + * Id of the appwidget shown on the lock screen when appwidgets are disabled. * @hide */ + @Deprecated @Readable - public static final String DARK_MODE_DIALOG_SEEN = - "dark_mode_dialog_seen"; + public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID = + "lock_screen_fallback_appwidget_id"; /** - * Custom time when Dark theme is scheduled to activate. - * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). + * Index of the lockscreen appwidget to restore, -1 if none. * @hide */ + @Deprecated @Readable - public static final String DARK_THEME_CUSTOM_START_TIME = - "dark_theme_custom_start_time"; + public static final String LOCK_SCREEN_STICKY_APPWIDGET = + "lock_screen_sticky_appwidget"; /** - * Custom time when Dark theme is scheduled to deactivate. - * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). + * This preference enables showing the owner info on LockScreen. * @hide + * @deprecated */ + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String DARK_THEME_CUSTOM_END_TIME = - "dark_theme_custom_end_time"; + public static final String LOCK_SCREEN_OWNER_INFO_ENABLED = + "lock_screen_owner_info_enabled"; /** - * Defines value returned by {@link android.service.autofill.UserData#getMaxUserDataSize()}. + * Indicates whether the user has allowed notifications to be shown atop a securely locked + * screen in their full "private" form (same as when the device is unlocked). + *

+ * Type: int (0 for false, 1 for true) * * @hide */ @SystemApi @Readable - public static final String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = - "autofill_user_data_max_user_data_size"; + public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = + "lock_screen_allow_private_notifications"; /** - * Defines value returned by - * {@link android.service.autofill.UserData#getMaxFieldClassificationIdsSize()}. - * + * When set by a user, allows notification remote input atop a securely locked screen + * without having to unlock * @hide */ - @SystemApi @Readable - public static final String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = - "autofill_user_data_max_field_classification_size"; + public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT = + "lock_screen_allow_remote_input"; /** - * Defines value returned by - * {@link android.service.autofill.UserData#getMaxCategoryCount()}. - * + * Indicates which clock face to show on lock screen and AOD formatted as a serialized + * {@link org.json.JSONObject} with the format: + * {"clock": id, "_applied_timestamp": timestamp} * @hide */ - @SystemApi @Readable - public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = - "autofill_user_data_max_category_count"; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face"; /** - * Defines value returned by {@link android.service.autofill.UserData#getMaxValueLength()}. - * + * Indicates which clock face to show on lock screen and AOD while docked. * @hide */ - @SystemApi @Readable - public static final String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = - "autofill_user_data_max_value_length"; + public static final String DOCKED_CLOCK_FACE = "docked_clock_face"; /** - * Defines value returned by {@link android.service.autofill.UserData#getMinValueLength()}. + * Setting to indicate that content filters should be enabled on web browsers. + * + *

    + *
  • non-positive (less or equal to 0) = Allow all sites + *
  • positive (greater than 0) = Try to block explicit sites + *
* * @hide */ - @SystemApi @Readable - public static final String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = - "autofill_user_data_min_value_length"; + public static final String BROWSER_CONTENT_FILTERS_ENABLED = + "browser_content_filters_enabled"; /** - * Defines whether Content Capture is enabled for the user. + * Setting to indicate that content filters should be enabled in web search engines. * - *

Type: {@code int} ({@code 0} for disabled, {@code 1} for enabled). - *

Default: enabled + *

    + *
  • non-positive (less or equal to 0) = Off + *
  • positive (greater than 0) = Filter + *
* * @hide */ - @TestApi @Readable - public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled"; + public static final String SEARCH_CONTENT_FILTERS_ENABLED = + "search_content_filters_enabled"; /** - * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead + * Setting to indicate that themes should be enabled in related app. + * + *
    + *
  • 0 = Off + *
  • 1 = Enable themes + *
+ * + * @hide */ - @Deprecated - public static final String DEVICE_PROVISIONED = Global.DEVICE_PROVISIONED; + public static final String PACK_THEME_FEATURE_ENABLED = + "pack_theme_feature_enabled"; /** - * Indicates whether a DPC has been downloaded during provisioning. - * - *

Type: int (0 for false, 1 for true) + * Setting to indicate that suggested themes feature should be enabled in related app. * - *

If this is true, then any attempts to begin setup again should result in factory reset + *

    + *
  • 0 = Off + *
  • 1 = Enable suggested themes + *
* * @hide */ - @Readable - public static final String MANAGED_PROVISIONING_DPC_DOWNLOADED = - "managed_provisioning_dpc_downloaded"; + public static final String SUGGESTED_THEME_FEATURE_ENABLED = + "suggested_theme_feature_enabled"; /** - * Indicates whether the device is under restricted secure FRP mode. - * Secure FRP mode is enabled when the device is under FRP. On solving of FRP challenge, - * device is removed from this mode. - *

- * Type: int (0 for false, 1 for true) - * - * @deprecated Use Global.SECURE_FRP_MODE + * String property which is a comma separated list of package names. These package names + * will be added to the existing agent allowlist. Since this contains package names, it must + * NOT be marked @Readable. + * @hide */ - @Deprecated - @Readable - public static final String SECURE_FRP_MODE = "secure_frp_mode"; + public static final String APP_FUNCTION_ADDITIONAL_AGENT_ALLOWLIST = + "app_function_additional_agent_allowlist"; /** - * Indicates whether the current user has completed setup via the setup wizard. - *

- * Type: int (0 for false, 1 for true) - * + * Set by the system to track if the user needs to see the call to action for + * the lockscreen notification policy. * @hide */ - @SystemApi @Readable - public static final String USER_SETUP_COMPLETE = "user_setup_complete"; + public static final String SHOW_NOTE_ABOUT_NOTIFICATION_HIDING = + "show_note_about_notification_hiding"; /** - * Indicates that the user has not started setup personalization. - * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. - * + * Set to 1 by the system after trust agents have been initialized. * @hide */ - @SystemApi - public static final int USER_SETUP_PERSONALIZATION_NOT_STARTED = 0; + @Readable + public static final String TRUST_AGENTS_INITIALIZED = + "trust_agents_initialized"; /** - * Indicates that the user has not yet completed setup personalization. - * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. - * + * Set to 1 by the system after the list of known trust agents have been initialized. * @hide */ - @SystemApi - public static final int USER_SETUP_PERSONALIZATION_STARTED = 1; + public static final String KNOWN_TRUST_AGENTS_INITIALIZED = + "known_trust_agents_initialized"; /** - * Indicates that the user has snoozed personalization and will complete it later. - * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. - * - * @hide + * The Logging ID (a unique 64-bit value) as a hex string. + * Used as a pseudonymous identifier for logging. + * @deprecated This identifier is poorly initialized and has + * many collisions. It should not be used. */ - @SystemApi - public static final int USER_SETUP_PERSONALIZATION_PAUSED = 2; + @Deprecated + @Readable + public static final String LOGGING_ID = "logging_id"; /** - * Indicates that the user has completed setup personalization. - * One of the possible states for {@link #USER_SETUP_PERSONALIZATION_STATE}. - * - * @hide + * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead */ - @SystemApi - public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - USER_SETUP_PERSONALIZATION_NOT_STARTED, - USER_SETUP_PERSONALIZATION_STARTED, - USER_SETUP_PERSONALIZATION_PAUSED, - USER_SETUP_PERSONALIZATION_COMPLETE - }) - public @interface UserSetupPersonalization {} + @Deprecated + public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; /** - * Defines the user's current state of device personalization. - * The possible states are defined in {@link UserSetupPersonalization}. - * - * @hide + * No longer supported. */ - @SystemApi @Readable - public static final String USER_SETUP_PERSONALIZATION_STATE = - "user_setup_personalization_state"; + public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled"; /** - * Whether the current user has been set up via setup wizard (0 = false, 1 = true) - * This value differs from USER_SETUP_COMPLETE in that it can be reset back to 0 - * in case SetupWizard has been re-enabled on TV devices. - * - * @hide + * No longer supported. */ @Readable - public static final String TV_USER_SETUP_COMPLETE = "tv_user_setup_complete"; + public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"; /** - * The prefix for a category name that indicates whether a suggested action from that - * category was marked as completed. - *

- * Type: int (0 for false, 1 for true) - * - * @hide + * No longer supported. */ - @SystemApi @Readable - public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category."; + public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; /** - * Whether or not compress blocks should be released on install. - *

The setting only determines if the platform will attempt to release - * compress blocks; it does not guarantee that the files will have their - * compress blocks released. Compression is currently only supported on - * some f2fs filesystems. - *

- * Type: int (0 for false, 1 for true) - * - * @hide + * Settings classname to launch when Settings is clicked from All + * Applications. Needed because of user testing between the old + * and new Settings apps. */ - public static final String RELEASE_COMPRESS_BLOCKS_ON_INSTALL = - "release_compress_blocks_on_install"; + // TODO: 881807 + @Readable + public static final String SETTINGS_CLASSNAME = "settings_classname"; /** - * List of input methods that are currently enabled. This is a string - * containing the IDs of all enabled input methods, each ID separated - * by ':'. - * - * Format like "ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0" - * where imeId is ComponentName and subtype is int32. - * - *

Note: This setting is not readable to the app targeting API level 34 or higher. use - * {@link android.view.inputmethod.InputMethodManager#getEnabledInputMethodList()} instead. + * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead */ - @Readable(maxTargetSdk = Build.VERSION_CODES.TIRAMISU) - public static final String ENABLED_INPUT_METHODS = "enabled_input_methods"; + @Deprecated + public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; /** - * List of system input methods that are currently disabled. This is a string - * containing the IDs of all disabled input methods, each ID separated - * by ':'. - * @hide + * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead */ - @Readable(maxTargetSdk = Build.VERSION_CODES.TIRAMISU) - public static final String DISABLED_SYSTEM_INPUT_METHODS = "disabled_system_input_methods"; + @Deprecated + public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; /** - * Whether to show the IME when a hard keyboard is connected. This is a boolean that - * determines if the IME should be shown when a hard keyboard is attached. - * @hide + * If accessibility is enabled. */ - @TestApi @Readable - @SuppressLint("NoSettingsProvider") - public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard"; + public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled"; /** - * Whether to enable bounce keys for Physical Keyboard accessibility. - * - * If set to non-zero value, any key press on physical keyboard within the provided - * threshold duration (in milliseconds) of the same key, will be ignored. - * + * Whether select sound track with audio description by default. * @hide */ - @Readable - public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys"; + public static final String ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT = + "enabled_accessibility_audio_description_by_default"; /** - * Whether to enable slow keys for Physical Keyboard accessibility. - * - * If set to non-zero value, any key press on physical keyboard needs to be pressed and - * held for the provided threshold duration (in milliseconds) to be registered in the - * system. - * + * Setting specifying if the accessibility shortcut is enabled. * @hide */ @Readable - public static final String ACCESSIBILITY_SLOW_KEYS = "accessibility_slow_keys"; + public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN = + "accessibility_shortcut_on_lock_screen"; /** - * Whether to enable sticky keys for Physical Keyboard accessibility. - * - * This is a boolean value that determines if Sticky keys feature is enabled. - * + * Setting specifying if the accessibility shortcut dialog has been shown to this user. * @hide */ @Readable - public static final String ACCESSIBILITY_STICKY_KEYS = "accessibility_sticky_keys"; + public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN = + "accessibility_shortcut_dialog_shown"; /** - * Whether stylus button presses are disabled. This is a boolean that - * determines if stylus buttons are ignored. + * Setting specifying if the timeout restriction + * {@link ViewConfiguration#getAccessibilityShortcutKeyTimeout()} + * of the accessibility shortcut dialog is skipped. * * @hide */ - @TestApi - @Readable - @SuppressLint("NoSettingsProvider") - public static final String STYLUS_BUTTONS_ENABLED = "stylus_buttons_enabled"; + public static final String SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION = + "skip_accessibility_shortcut_dialog_timeout_restriction"; /** - * Preferred default user profile to use with the notes task button shortcut. + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via the accessibility shortcut. * + *

This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. * @hide */ - @SuppressLint("NoSettingsProvider") - public static final String DEFAULT_NOTE_TASK_PROFILE = "default_note_task_profile"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi + @Readable + public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = + "accessibility_shortcut_target_service"; /** - * Host name and port for global http proxy. Uses ':' seperator for - * between host and port. - * - * @deprecated Use {@link Global#HTTP_PROXY} + * Setting specifying the accessibility service or feature to be toggled via the + * accessibility button in the navigation bar. This is either a flattened + * {@link ComponentName} or the class name of a system class implementing a supported + * accessibility feature. + * @hide */ - @Deprecated - public static final String HTTP_PROXY = Global.HTTP_PROXY; + @Readable + public static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT = + "accessibility_button_target_component"; /** - * Package designated as always-on VPN provider. + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via the accessibility button in the navigation bar, + * or the floating accessibility button. * + *

This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. * @hide */ - public static final String ALWAYS_ON_VPN_APP = "always_on_vpn_app"; + @Readable + public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets"; /** - * Whether to block networking outside of VPN connections while always-on is set. - * @see #ALWAYS_ON_VPN_APP + * Setting specifying the accessibility services, shortcut targets or features + * to be toggled via the gesture shortcut * + *

This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class + * implementing a supported accessibility feature. * @hide */ @Readable - public static final String ALWAYS_ON_VPN_LOCKDOWN = "always_on_vpn_lockdown"; + public static final String ACCESSIBILITY_GESTURE_TARGETS = + "accessibility_gesture_targets"; /** - * Comma separated list of packages that are allowed to access the network when VPN is in - * lockdown mode but not running. - * @see #ALWAYS_ON_VPN_LOCKDOWN + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via a tile in the quick settings panel. * + *

This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. * @hide */ - @Readable(maxTargetSdk = Build.VERSION_CODES.S) - public static final String ALWAYS_ON_VPN_LOCKDOWN_WHITELIST = - "always_on_vpn_lockdown_whitelist"; + public static final String ACCESSIBILITY_QS_TARGETS = "accessibility_qs_targets"; /** - * Whether applications can be installed for this user via the system's - * {@link Intent#ACTION_INSTALL_PACKAGE} mechanism. + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via a keyboard shortcut gesture. * - *

1 = permit app installation via the system package installer intent - *

0 = do not allow use of the package installer - * @deprecated Starting from {@link android.os.Build.VERSION_CODES#O}, apps should use - * {@link PackageManager#canRequestPackageInstalls()} - * @see PackageManager#canRequestPackageInstalls() + *

This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. + * + * @hide */ - @Deprecated - @Readable - public static final String INSTALL_NON_MARKET_APPS = "install_non_market_apps"; + public static final String ACCESSIBILITY_KEY_GESTURE_TARGETS = + "accessibility_key_gesture_targets"; /** - * A flag to tell {@link com.android.server.devicepolicy.DevicePolicyManagerService} that - * the default for {@link #INSTALL_NON_MARKET_APPS} is reversed for this user on OTA. So it - * can set the restriction {@link android.os.UserManager#DISALLOW_INSTALL_UNKNOWN_SOURCES} - * on behalf of the profile owner if needed to make the change transparent for profile - * owners. + * The system class name of magnification controller which is a target to be toggled via + * accessibility shortcut or accessibility button. * * @hide */ @Readable - public static final String UNKNOWN_SOURCES_DEFAULT_REVERSED = - "unknown_sources_default_reversed"; + public static final String ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER = + "com.android.server.accessibility.MagnificationController"; /** - * Comma-separated list of location providers that are enabled. Do not rely on this value - * being present or correct, or on ContentObserver notifications on the corresponding Uri. - * - * @deprecated This setting no longer exists from Android S onwards as it no longer is - * capable of realistically reflecting location settings. Use {@link - * LocationManager#isProviderEnabled(String)} or {@link LocationManager#isLocationEnabled()} - * instead. + * If touch exploration is enabled. */ - @Deprecated @Readable - public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; + public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"; /** - * The current location mode of the device. Do not rely on this value being present or on - * ContentObserver notifications on the corresponding Uri. - * - * @deprecated The preferred methods for checking location mode and listening for changes - * are via {@link LocationManager#isLocationEnabled()} and - * {@link LocationManager#MODE_CHANGED_ACTION}. + * List of the enabled accessibility providers. */ - @Deprecated @Readable - public static final String LOCATION_MODE = "location_mode"; + public static final String ENABLED_ACCESSIBILITY_SERVICES = + "enabled_accessibility_services"; /** - * The App or module that changes the location mode. + * List of the notified non-accessibility category accessibility services. + * * @hide */ @Readable - public static final String LOCATION_CHANGER = "location_changer"; + public static final String NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES = + "notified_non_accessibility_category_services"; /** - * The location changer is unknown or unable to detect. + * List of the accessibility services to which the user has granted + * permission to put the device into touch exploration mode. + * * @hide */ - public static final int LOCATION_CHANGER_UNKNOWN = 0; + @Readable + public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES = + "touch_exploration_granted_accessibility_services"; /** - * Location settings in system settings. + * Is talkback service enabled or not. 0 == no, 1 == yes + * * @hide */ - public static final int LOCATION_CHANGER_SYSTEM_SETTINGS = 1; + public static final String WEAR_TALKBACK_ENABLED = "wear_talkback_enabled"; /** - * The location icon in drop down notification drawer. + * Whether the Global Actions Panel is enabled. * @hide */ - public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2; + @Readable + public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "global_actions_panel_enabled"; /** - * Location mode is off. + * Whether the Global Actions Panel can be toggled on or off in Settings. + * @hide */ - public static final int LOCATION_MODE_OFF = 0; + @Readable + public static final String GLOBAL_ACTIONS_PANEL_AVAILABLE = + "global_actions_panel_available"; /** - * This mode no longer has any distinct meaning, but is interpreted as the location mode is - * on. - * - * @deprecated See {@link #LOCATION_MODE}. + * Enables debug mode for the Global Actions Panel. + * @hide */ - @Deprecated - public static final int LOCATION_MODE_SENSORS_ONLY = 1; + @Readable + public static final String GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED = + "global_actions_panel_debug_enabled"; /** - * This mode no longer has any distinct meaning, but is interpreted as the location mode is - * on. - * - * @deprecated See {@link #LOCATION_MODE}. + * Whether the hush gesture has ever been used + * @hide */ - @Deprecated - public static final int LOCATION_MODE_BATTERY_SAVING = 2; + @SystemApi + @Readable + public static final String HUSH_GESTURE_USED = "hush_gesture_used"; /** - * This mode no longer has any distinct meaning, but is interpreted as the location mode is - * on. - * - * @deprecated See {@link #LOCATION_MODE}. + * Number of times the user has manually clicked the ringer toggle + * @hide */ - @Deprecated - public static final int LOCATION_MODE_HIGH_ACCURACY = 3; + @Readable + public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count"; /** - * Location mode is on. - * + * Whether to play a sound for charging events. * @hide */ - @SystemApi - public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY; + @Readable + public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled"; /** - * The current location time zone detection enabled state for the user. - * - * See {@link android.app.time.TimeManager#getTimeZoneCapabilitiesAndConfig} for access. - * See {@link android.app.time.TimeManager#updateTimeZoneConfiguration} to update. + * Whether to vibrate for charging events. * @hide */ - public static final String LOCATION_TIME_ZONE_DETECTION_ENABLED = - "location_time_zone_detection_enabled"; + @Readable + public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled"; /** - * The accuracy in meters used for coarsening location for clients with only the coarse - * location permission. - * + * If 0, turning on dnd manually will last indefinitely. + * Else if non-negative, turning on dnd manually will last for this many minutes. + * Else (if negative), turning on dnd manually will surface a dialog that prompts + * user to specify a duration. * @hide */ @Readable - public static final String LOCATION_COARSE_ACCURACY_M = "locationCoarseAccuracy"; + public static final String ZEN_DURATION = "zen_duration"; + + /** @hide */ public static final int ZEN_DURATION_PROMPT = -1; + /** @hide */ public static final int ZEN_DURATION_FOREVER = 0; /** - * Whether or not to show display system location accesses. + * Whether the in call notification is enabled to play sound during calls. The value is + * boolean (1 or 0). * @hide */ - public static final String LOCATION_SHOW_SYSTEM_OPS = "locationShowSystemOps"; + @Readable + public static final String IN_CALL_NOTIFICATION_ENABLED = "in_call_notification_enabled"; /** - * A flag containing settings used for biometric weak + * Uri of the slice that's presented on the keyguard. + * Defaults to a slice with the date and next alarm. + * * @hide */ - @Deprecated @Readable - public static final String LOCK_BIOMETRIC_WEAK_FLAGS = - "lock_biometric_weak_flags"; + public static final String KEYGUARD_SLICE_URI = "keyguard_slice_uri"; /** - * Whether lock-to-app will lock the keyguard when exiting. + * The adjustment in font weight. This is used to draw text in bold. + * + *

This value can be negative. To display bolded text, the adjustment used is 300, + * which is the difference between + * {@link android.graphics.fonts.FontStyle#FONT_WEIGHT_NORMAL} and + * {@link android.graphics.fonts.FontStyle#FONT_WEIGHT_BOLD}. + * * @hide */ @Readable - public static final String LOCK_TO_APP_EXIT_LOCKED = "lock_to_app_exit_locked"; + public static final String FONT_WEIGHT_ADJUSTMENT = "font_weight_adjustment"; /** - * Whether autolock is enabled (0 = false, 1 = true) + * Whether to speak passwords while in accessibility mode. * - * @deprecated Use {@link android.app.KeyguardManager} to determine the state and security - * level of the keyguard. Accessing this setting from an app that is targeting - * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. + * @deprecated The speaking of passwords is controlled by individual accessibility services. + * Apps should ignore this setting and provide complete information to accessibility + * at all times, which was the behavior when this value was {@code true}. */ @Deprecated @Readable - public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; + public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; /** - * Whether lock pattern is visible as user enters (0 = false, 1 = true) + * Whether to draw text with high contrast while in accessibility mode. * - * @deprecated Accessing this setting from an app that is targeting - * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. + * @hide */ - @Deprecated @Readable - public static final String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern"; + public static final String ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED = + "high_text_contrast_enabled"; /** - * Whether lock pattern will vibrate as user enters (0 = false, 1 = - * true) + * Setting that specifies the status of the High Contrast Text + * rectangle refresh's one-time prompt. + * 0 = UNKNOWN + * 1 = PROMPT_SHOWN + * 2 = PROMPT_UNNECESSARY * - * @deprecated Starting in {@link VERSION_CODES#JELLY_BEAN_MR1} the - * lockscreen uses - * {@link Settings.System#HAPTIC_FEEDBACK_ENABLED}. - * Accessing this setting from an app that is targeting - * {@link VERSION_CODES#M} or later throws a {@code SecurityException}. + * @hide */ - @Deprecated - @Readable - public static final String - LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled"; + public static final String ACCESSIBILITY_HCT_RECT_PROMPT_STATUS = + "accessibility_hct_rect_prompt_status"; /** - * Determines the width and height of the LockPatternView widget + * The color contrast, float in [-1, 1], 1 being the highest contrast. + * * @hide */ - public static final String LOCK_PATTERN_SIZE = "lock_pattern_size"; + public static final String CONTRAST_LEVEL = "contrast_level"; /** - * Whether lock pattern will show dots (0 = false, 1 = true) + * Setting that specifies whether the display magnification is enabled via a system-wide + * triple tap gesture. Display magnifications allows the user to zoom in the display content + * and is targeted to low vision users. The current magnification scale is controlled by + * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. + * * @hide */ - public static final String LOCK_DOTS_VISIBLE = "lock_pattern_dotsvisible"; + @UnsupportedAppUsage + @TestApi + @Readable + public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = + "accessibility_display_magnification_enabled"; /** - * Whether lockscreen error pattern is visible (0 = false, 1 = true) + * Setting that specifies whether the display magnification is enabled via a shortcut + * affordance within the system's navigation area. Display magnifications allows the user to + * zoom in the display content and is targeted to low vision users. The current + * magnification scale is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. + * + * @deprecated Use {@link #ACCESSIBILITY_BUTTON_TARGETS} instead. + * {@link #ACCESSIBILITY_BUTTON_TARGETS} holds the magnification system class name + * when navigation bar magnification is enabled. * @hide */ - public static final String LOCK_SHOW_ERROR_PATH = "lock_pattern_show_error_path"; + @SystemApi + @Readable + public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = + "accessibility_display_magnification_navbar_enabled"; /** - * This preference allows the device to be locked given time after screen goes off, - * subject to current DeviceAdmin policy limits. + * Setting that specifies what the display magnification scale is. + * Display magnifications allows the user to zoom in the display + * content and is targeted to low vision users. Whether a display + * magnification is performed is controlled by + * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED} and + * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED} + * * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String LOCK_SCREEN_LOCK_AFTER_TIMEOUT = "lock_screen_lock_after_timeout"; + public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE = + "accessibility_display_magnification_scale"; /** - * This preference contains the string that shows for owner info on LockScreen. + * Unused mangnification setting + * * @hide * @deprecated */ @Deprecated @Readable - public static final String LOCK_SCREEN_OWNER_INFO = "lock_screen_owner_info"; + public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE = + "accessibility_display_magnification_auto_update"; /** - * Ids of the user-selected appwidgets on the lockscreen (comma-delimited). + * Accessibility Window Magnification Allow diagonal scrolling value. The value is boolean. + * 1 : on, 0 : off + * * @hide */ - @Deprecated - @Readable - public static final String LOCK_SCREEN_APPWIDGET_IDS = - "lock_screen_appwidget_ids"; + public static final String ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING = + "accessibility_allow_diagonal_scrolling"; + /** - * Id of the appwidget shown on the lock screen when appwidgets are disabled. + * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be + * modified from an AccessibilityService using the SoftKeyboardController. + * * @hide */ - @Deprecated @Readable - public static final String LOCK_SCREEN_FALLBACK_APPWIDGET_ID = - "lock_screen_fallback_appwidget_id"; + public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE = + "accessibility_soft_keyboard_mode"; /** - * Index of the lockscreen appwidget to restore, -1 if none. + * Default soft keyboard behavior. + * + * @hide + */ + public static final int SHOW_MODE_AUTO = 0; + + /** + * Soft keyboard is never shown. + * * @hide */ - @Deprecated - @Readable - public static final String LOCK_SCREEN_STICKY_APPWIDGET = - "lock_screen_sticky_appwidget"; + public static final int SHOW_MODE_HIDDEN = 1; /** - * This preference enables showing the owner info on LockScreen. + * Setting that specifies whether timed text (captions) should be + * displayed in video content. Text display properties are controlled by + * the following settings: + *

    + *
  • {@link #ACCESSIBILITY_CAPTIONING_LOCALE} + *
  • {@link #ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR} + *
  • {@link #ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR} + *
  • {@link #ACCESSIBILITY_CAPTIONING_EDGE_COLOR} + *
  • {@link #ACCESSIBILITY_CAPTIONING_EDGE_TYPE} + *
  • {@link #ACCESSIBILITY_CAPTIONING_TYPEFACE} + *
  • {@link #ACCESSIBILITY_CAPTIONING_FONT_SCALE} + *
+ * * @hide - * @deprecated */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String LOCK_SCREEN_OWNER_INFO_ENABLED = - "lock_screen_owner_info_enabled"; + public static final String ACCESSIBILITY_CAPTIONING_ENABLED = + "accessibility_captioning_enabled"; /** - * Indicates whether the user has allowed notifications to be shown atop a securely locked - * screen in their full "private" form (same as when the device is unlocked). - *

- * Type: int (0 for false, 1 for true) + * Setting that specifies the language for captions as a locale string, + * e.g. en_US. * + * @see java.util.Locale#toString * @hide */ - @SystemApi @Readable - public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = - "lock_screen_allow_private_notifications"; + public static final String ACCESSIBILITY_CAPTIONING_LOCALE = + "accessibility_captioning_locale"; /** - * When set by a user, allows notification remote input atop a securely locked screen - * without having to unlock + * Integer property that specifies the preset style for captions, one + * of: + *

    + *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESET_CUSTOM} + *
  • a valid index of {@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESETS} + *
+ * + * @see java.util.Locale#toString * @hide */ @Readable - public static final String LOCK_SCREEN_ALLOW_REMOTE_INPUT = - "lock_screen_allow_remote_input"; + public static final String ACCESSIBILITY_CAPTIONING_PRESET = + "accessibility_captioning_preset"; /** - * Indicates which clock face to show on lock screen and AOD formatted as a serialized - * {@link org.json.JSONObject} with the format: - * {"clock": id, "_applied_timestamp": timestamp} + * Integer property that specifes the background color for captions as a + * packed 32-bit color. + * + * @see android.graphics.Color#argb * @hide */ @Readable - public static final String LOCK_SCREEN_CUSTOM_CLOCK_FACE = "lock_screen_custom_clock_face"; + public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR = + "accessibility_captioning_background_color"; /** - * Indicates which clock face to show on lock screen and AOD while docked. + * Integer property that specifes the foreground color for captions as a + * packed 32-bit color. + * + * @see android.graphics.Color#argb * @hide */ @Readable - public static final String DOCKED_CLOCK_FACE = "docked_clock_face"; + public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR = + "accessibility_captioning_foreground_color"; /** - * Setting to indicate that content filters should be enabled on web browsers. - * + * Integer property that specifes the edge type for captions, one of: *
    - *
  • non-positive (less or equal to 0) = Allow all sites - *
  • positive (greater than 0) = Try to block explicit sites + *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_NONE} + *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_OUTLINE} + *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_DROP_SHADOW} *
* + * @see #ACCESSIBILITY_CAPTIONING_EDGE_COLOR * @hide */ @Readable - public static final String BROWSER_CONTENT_FILTERS_ENABLED = - "browser_content_filters_enabled"; + public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE = + "accessibility_captioning_edge_type"; /** - * Setting to indicate that content filters should be enabled in web search engines. - * - *
    - *
  • non-positive (less or equal to 0) = Off - *
  • positive (greater than 0) = Filter - *
+ * Integer property that specifes the edge color for captions as a + * packed 32-bit color. * + * @see #ACCESSIBILITY_CAPTIONING_EDGE_TYPE + * @see android.graphics.Color#argb * @hide */ @Readable - public static final String SEARCH_CONTENT_FILTERS_ENABLED = - "search_content_filters_enabled"; + public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR = + "accessibility_captioning_edge_color"; /** - * Setting to indicate that themes should be enabled in related app. - * - *
    - *
  • 0 = Off - *
  • 1 = Enable themes - *
+ * Integer property that specifes the window color for captions as a + * packed 32-bit color. * + * @see android.graphics.Color#argb * @hide */ - public static final String PACK_THEME_FEATURE_ENABLED = - "pack_theme_feature_enabled"; + @Readable + public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR = + "accessibility_captioning_window_color"; /** - * Setting to indicate that suggested themes feature should be enabled in related app. - * + * String property that specifies the typeface for captions, one of: *
    - *
  • 0 = Off - *
  • 1 = Enable suggested themes + *
  • DEFAULT + *
  • MONOSPACE + *
  • SANS_SERIF + *
  • SERIF *
* + * @see android.graphics.Typeface * @hide */ - public static final String SUGGESTED_THEME_FEATURE_ENABLED = - "suggested_theme_feature_enabled"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Readable + public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE = + "accessibility_captioning_typeface"; /** - * String property which is a comma separated list of package names. These package names - * will be added to the existing agent allowlist. Since this contains package names, it must - * NOT be marked @Readable. + * Floating point property that specifies font scaling for captions. + * * @hide */ - public static final String APP_FUNCTION_ADDITIONAL_AGENT_ALLOWLIST = - "app_function_additional_agent_allowlist"; + @Readable + public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE = + "accessibility_captioning_font_scale"; /** - * Set by the system to track if the user needs to see the call to action for - * the lockscreen notification policy. - * @hide + * Setting that specifies whether display color inversion is enabled. */ @Readable - public static final String SHOW_NOTE_ABOUT_NOTIFICATION_HIDING = - "show_note_about_notification_hiding"; + public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = + "accessibility_display_inversion_enabled"; /** - * Set to 1 by the system after trust agents have been initialized. + * Flag that specifies whether font size has been changed. The flag will + * be set when users change the scaled value of font size for the first time. * @hide */ @Readable - public static final String TRUST_AGENTS_INITIALIZED = - "trust_agents_initialized"; + public static final String ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED = + "accessibility_font_scaling_has_been_changed"; /** - * Set to 1 by the system after the list of known trust agents have been initialized. + * Setting that specifies whether display color space adjustment is + * enabled. + * * @hide */ - public static final String KNOWN_TRUST_AGENTS_INITIALIZED = - "known_trust_agents_initialized"; - - /** - * The Logging ID (a unique 64-bit value) as a hex string. - * Used as a pseudonymous identifier for logging. - * @deprecated This identifier is poorly initialized and has - * many collisions. It should not be used. - */ - @Deprecated + @UnsupportedAppUsage @Readable - public static final String LOGGING_ID = "logging_id"; + public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED = + "accessibility_display_daltonizer_enabled"; /** - * @deprecated Use {@link android.provider.Settings.Global#NETWORK_PREFERENCE} instead + * Integer property that specifies the type of color space adjustment to + * perform. Valid values are defined in AccessibilityManager and Settings arrays.xml: + * - AccessibilityManager.DALTONIZER_DISABLED = -1 + * - AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY = 0 + * - @string/daltonizer_mode_protanomaly = 11 + * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY and + * @string/daltonizer_mode_deuteranomaly = 12 + * - @string/daltonizer_mode_tritanomaly = 13 + * + * @hide */ - @Deprecated - public static final String NETWORK_PREFERENCE = Global.NETWORK_PREFERENCE; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Readable + public static final String ACCESSIBILITY_DISPLAY_DALTONIZER = + "accessibility_display_daltonizer"; /** - * No longer supported. + * Integer property that determines the saturation level of color correction. Default value + * is defined in Settings config.xml. + * [0-10] inclusive where 0 would look as if color space adustment is not applied at all. + * + * @hide */ - @Readable - public static final String PARENTAL_CONTROL_ENABLED = "parental_control_enabled"; + public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL = + "accessibility_display_daltonizer_saturation_level"; /** - * No longer supported. + * Setting that specifies whether automatic click when the mouse pointer stops moving is + * enabled. + * + * @hide */ + @UnsupportedAppUsage @Readable - public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update"; + public static final String ACCESSIBILITY_AUTOCLICK_ENABLED = + "accessibility_autoclick_enabled"; /** - * No longer supported. + * Integer setting specifying amount of time in ms the mouse pointer has to stay still + * before performing click when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide */ @Readable - public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url"; + public static final String ACCESSIBILITY_AUTOCLICK_DELAY = + "accessibility_autoclick_delay"; /** - * Settings classname to launch when Settings is clicked from All - * Applications. Needed because of user testing between the old - * and new Settings apps. + * Integer setting specifying the autoclick cursor area size (the radius of the autoclick + * ring indicator) when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide */ - // TODO: 881807 - @Readable - public static final String SETTINGS_CLASSNAME = "settings_classname"; + public static final String ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE = + "accessibility_autoclick_cursor_area_size"; /** - * @deprecated Use {@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED} instead + * Setting that specifies whether minor cursor movement will be ignored when + * {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide */ - @Deprecated - public static final String USB_MASS_STORAGE_ENABLED = Global.USB_MASS_STORAGE_ENABLED; + public static final String ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT = + "accessibility_autoclick_ignore_minor_cursor_movement"; /** - * @deprecated Use {@link android.provider.Settings.Global#USE_GOOGLE_MAIL} instead + * String setting that stores the position of the autoclick panel when + * {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. The position is stored as a + * comma-separated string containing gravity, x-coordinate, y-coordinate, and corner index. + * For example, "8388659,15,30,0", where 8388659 means gravity Gravity.START | Gravity.TOP. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide */ - @Deprecated - public static final String USE_GOOGLE_MAIL = Global.USE_GOOGLE_MAIL; + public static final String ACCESSIBILITY_AUTOCLICK_PANEL_POSITION = + "accessibility_autoclick_panel_position"; /** - * If accessibility is enabled. + * Setting that specifies whether autoclick type reverts to left click after performing + * an action when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * + * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * @hide */ - @Readable - public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled"; + public static final String ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK = + "accessibility_autoclick_revert_to_left_click"; /** - * Whether select sound track with audio description by default. + * Whether or not larger size icons are used for the pointer of mouse/trackpad for + * accessibility. + * (0 = false, 1 = true) + * + * @deprecated This setting is no longer in use, as the size of pointer icons is now + * controlled by the {@link #POINTER_SCALE} setting. The value of this setting + * is ignored. * @hide */ - public static final String ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT = - "enabled_accessibility_audio_description_by_default"; + @UnsupportedAppUsage + @Readable + @Deprecated + public static final String ACCESSIBILITY_LARGE_POINTER_ICON = + "accessibility_large_pointer_icon"; /** - * Setting specifying if the accessibility shortcut is enabled. + * The timeout for considering a press to be a long press in milliseconds. * @hide */ + @UnsupportedAppUsage @Readable - public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN = - "accessibility_shortcut_on_lock_screen"; + @TestApi + @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. + public static final String LONG_PRESS_TIMEOUT = "long_press_timeout"; /** - * Setting specifying if the accessibility shortcut dialog has been shown to this user. + * The duration in milliseconds between the first tap's up event and the second tap's + * down event for an interaction to be considered part of the same multi-press. * @hide */ @Readable - public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN = - "accessibility_shortcut_dialog_shown"; + @TestApi + @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. + public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout"; /** - * Setting specifying if the timeout restriction - * {@link ViewConfiguration#getAccessibilityShortcutKeyTimeout()} - * of the accessibility shortcut dialog is skipped. + * Whether to enable key repeats for Physical Keyboard. * + * If set to false, continuous key presses on + * physical keyboard will not cause the pressed key to repeated. * @hide */ - public static final String SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION = - "skip_accessibility_shortcut_dialog_timeout_restriction"; + @Readable + public static final String KEY_REPEAT_ENABLED = "key_repeat_enabled"; /** - * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via the accessibility shortcut. - * - *

This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class implementing a supported - * accessibility feature. + * The duration before a key repeat begins in milliseconds. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi @Readable - public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE = - "accessibility_shortcut_target_service"; + public static final String KEY_REPEAT_TIMEOUT_MS = "key_repeat_timeout"; /** - * Setting specifying the accessibility service or feature to be toggled via the - * accessibility button in the navigation bar. This is either a flattened - * {@link ComponentName} or the class name of a system class implementing a supported - * accessibility feature. + * The duration between successive key repeats in milliseconds. * @hide */ @Readable - public static final String ACCESSIBILITY_BUTTON_TARGET_COMPONENT = - "accessibility_button_target_component"; + public static final String KEY_REPEAT_DELAY_MS = "key_repeat_delay"; /** - * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via the accessibility button in the navigation bar, - * or the floating accessibility button. + * Setting that specifies recommended timeout in milliseconds for controls + * which don't need user's interactions. * - *

This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class implementing a supported - * accessibility feature. * @hide */ @Readable - public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets"; + public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS = + "accessibility_non_interactive_ui_timeout_ms"; /** - * Setting specifying the accessibility services, shortcut targets or features - * to be toggled via the gesture shortcut + * Setting that specifies recommended timeout in milliseconds for controls + * which need user's interactions. * - *

This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class - * implementing a supported accessibility feature. * @hide */ @Readable - public static final String ACCESSIBILITY_GESTURE_TARGETS = - "accessibility_gesture_targets"; + public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS = + "accessibility_interactive_ui_timeout_ms"; + /** - * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via a tile in the quick settings panel. + * Setting that specifies whether Reduce Bright Colors, or brightness dimming by color + * adjustment, is enabled. * - *

This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class implementing a supported - * accessibility feature. * @hide */ - public static final String ACCESSIBILITY_QS_TARGETS = "accessibility_qs_targets"; + public static final String REDUCE_BRIGHT_COLORS_ACTIVATED = + "reduce_bright_colors_activated"; /** - * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via a keyboard shortcut gesture. - * - *

This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class implementing a supported - * accessibility feature. + * Setting that specifies the level of Reduce Bright Colors in intensity. The range is + * [0, 100]. * * @hide */ - public static final String ACCESSIBILITY_KEY_GESTURE_TARGETS = - "accessibility_key_gesture_targets"; + public static final String REDUCE_BRIGHT_COLORS_LEVEL = + "reduce_bright_colors_level"; /** - * The system class name of magnification controller which is a target to be toggled via - * accessibility shortcut or accessibility button. + * Setting that specifies whether Reduce Bright Colors should persist across reboots. * * @hide */ - @Readable - public static final String ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER = - "com.android.server.accessibility.MagnificationController"; + public static final String REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS = + "reduce_bright_colors_persist_across_reboots"; /** - * If touch exploration is enabled. + * Integer setting that specifies the duration in ms required to invert the text cursor's + * pixels. + * + * @see ViewConfiguration#getTextCursorBlinkIntervalMillis() + * + * @hide */ - @Readable - public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled"; + public static final String ACCESSIBILITY_TEXT_CURSOR_BLINK_INTERVAL_MS = + "accessibility_text_cursor_blink_interval_ms"; /** - * List of the enabled accessibility providers. + * Setting that holds EM_VALUE (proprietary) + * + * @hide */ - @Readable - public static final String ENABLED_ACCESSIBILITY_SERVICES = - "enabled_accessibility_services"; - + public static final String EM_VALUE = + "em_value"; /** - * List of the notified non-accessibility category accessibility services. + * Setting that specifies whether High Dynamic Range brightness is enabled. * * @hide */ - @Readable - public static final String NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES = - "notified_non_accessibility_category_services"; + public static final String HDR_BRIGHTNESS_ENABLED = + "hdr_brightness_enabled"; /** - * List of the accessibility services to which the user has granted - * permission to put the device into touch exploration mode. + * Setting that specifies the intensity of the High Dynamic Range brightness. The range is + * [0, 1], which is which is used to scale the HDR/SDR ratio. * * @hide */ - @Readable - public static final String TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES = - "touch_exploration_granted_accessibility_services"; + public static final String HDR_BRIGHTNESS_BOOST_LEVEL = + "hdr_brightness_boost_level"; /** - * Is talkback service enabled or not. 0 == no, 1 == yes + * List of the enabled print services. + * + * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade + * from pre-N. * * @hide */ - public static final String WEAR_TALKBACK_ENABLED = "wear_talkback_enabled"; + @UnsupportedAppUsage + @Readable + public static final String ENABLED_PRINT_SERVICES = + "enabled_print_services"; /** - * Whether the Global Actions Panel is enabled. + * List of the disabled print services. + * * @hide */ + @TestApi @Readable - public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "global_actions_panel_enabled"; + public static final String DISABLED_PRINT_SERVICES = + "disabled_print_services"; /** - * Whether the Global Actions Panel can be toggled on or off in Settings. + * The saved value for WindowManagerService.setForcedDisplayDensity() + * formatted as a single integer representing DPI. If unset, then use + * the real display density. + * * @hide */ @Readable - public static final String GLOBAL_ACTIONS_PANEL_AVAILABLE = - "global_actions_panel_available"; + public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; /** - * Enables debug mode for the Global Actions Panel. - * @hide + * Setting to always use the default text-to-speech settings regardless + * of the application settings. + * 1 = override application settings, + * 0 = use application settings (if specified). + * + * @deprecated The value of this setting is no longer respected by + * the framework text to speech APIs as of the Ice Cream Sandwich release. */ + @Deprecated @Readable - public static final String GLOBAL_ACTIONS_PANEL_DEBUG_ENABLED = - "global_actions_panel_debug_enabled"; + public static final String TTS_USE_DEFAULTS = "tts_use_defaults"; /** - * Whether the hush gesture has ever been used - * @hide + * Default text-to-speech engine speech rate. 100 = 1x */ - @SystemApi @Readable - public static final String HUSH_GESTURE_USED = "hush_gesture_used"; + public static final String TTS_DEFAULT_RATE = "tts_default_rate"; /** - * Number of times the user has manually clicked the ringer toggle - * @hide + * Default text-to-speech engine pitch. 100 = 1x */ @Readable - public static final String MANUAL_RINGER_TOGGLE_COUNT = "manual_ringer_toggle_count"; + public static final String TTS_DEFAULT_PITCH = "tts_default_pitch"; /** - * Whether to play a sound for charging events. - * @hide + * Default text-to-speech engine. */ @Readable - public static final String CHARGING_SOUNDS_ENABLED = "charging_sounds_enabled"; + public static final String TTS_DEFAULT_SYNTH = "tts_default_synth"; /** - * Whether to vibrate for charging events. - * @hide + * Default text-to-speech language. + * + * @deprecated this setting is no longer in use, as of the Ice Cream + * Sandwich release. Apps should never need to read this setting directly, + * instead can query the TextToSpeech framework classes for the default + * locale. {@link TextToSpeech#getLanguage()}. */ + @Deprecated @Readable - public static final String CHARGING_VIBRATION_ENABLED = "charging_vibration_enabled"; + public static final String TTS_DEFAULT_LANG = "tts_default_lang"; /** - * If 0, turning on dnd manually will last indefinitely. - * Else if non-negative, turning on dnd manually will last for this many minutes. - * Else (if negative), turning on dnd manually will surface a dialog that prompts - * user to specify a duration. - * @hide + * Default text-to-speech country. + * + * @deprecated this setting is no longer in use, as of the Ice Cream + * Sandwich release. Apps should never need to read this setting directly, + * instead can query the TextToSpeech framework classes for the default + * locale. {@link TextToSpeech#getLanguage()}. */ + @Deprecated @Readable - public static final String ZEN_DURATION = "zen_duration"; - - /** @hide */ public static final int ZEN_DURATION_PROMPT = -1; - /** @hide */ public static final int ZEN_DURATION_FOREVER = 0; + public static final String TTS_DEFAULT_COUNTRY = "tts_default_country"; /** - * Whether the in call notification is enabled to play sound during calls. The value is - * boolean (1 or 0). - * @hide + * Default text-to-speech locale variant. + * + * @deprecated this setting is no longer in use, as of the Ice Cream + * Sandwich release. Apps should never need to read this setting directly, + * instead can query the TextToSpeech framework classes for the + * locale that is in use {@link TextToSpeech#getLanguage()}. */ + @Deprecated @Readable - public static final String IN_CALL_NOTIFICATION_ENABLED = "in_call_notification_enabled"; + public static final String TTS_DEFAULT_VARIANT = "tts_default_variant"; /** - * Uri of the slice that's presented on the keyguard. - * Defaults to a slice with the date and next alarm. + * Stores the default tts locales on a per engine basis. Stored as + * a comma seperated list of values, each value being of the form + * {@code engine_name:locale} for example, + * {@code com.foo.ttsengine:eng-USA,com.bar.ttsengine:esp-ESP}. This + * supersedes {@link #TTS_DEFAULT_LANG}, {@link #TTS_DEFAULT_COUNTRY} and + * {@link #TTS_DEFAULT_VARIANT}. Apps should never need to read this + * setting directly, and can query the TextToSpeech framework classes + * for the locale that is in use. * * @hide */ @Readable - public static final String KEYGUARD_SLICE_URI = "keyguard_slice_uri"; + public static final String TTS_DEFAULT_LOCALE = "tts_default_locale"; /** - * The adjustment in font weight. This is used to draw text in bold. - * - *

This value can be negative. To display bolded text, the adjustment used is 300, - * which is the difference between - * {@link android.graphics.fonts.FontStyle#FONT_WEIGHT_NORMAL} and - * {@link android.graphics.fonts.FontStyle#FONT_WEIGHT_BOLD}. - * - * @hide + * Space delimited list of plugin packages that are enabled. */ @Readable - public static final String FONT_WEIGHT_ADJUSTMENT = "font_weight_adjustment"; + public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins"; /** - * Whether to speak passwords while in accessibility mode. - * - * @deprecated The speaking of passwords is controlled by individual accessibility services. - * Apps should ignore this setting and provide complete information to accessibility - * at all times, which was the behavior when this value was {@code true}. + * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} + * instead. */ @Deprecated - @Readable - public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password"; + public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = + Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; /** - * Whether to draw text with high contrast while in accessibility mode. - * - * @hide + * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} + * instead. */ - @Readable - public static final String ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED = - "high_text_contrast_enabled"; + @Deprecated + public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = + Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; /** - * Setting that specifies the status of the High Contrast Text - * rectangle refresh's one-time prompt. - * 0 = UNKNOWN - * 1 = PROMPT_SHOWN - * 2 = PROMPT_UNNECESSARY - * - * @hide + * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT} + * instead. */ - public static final String ACCESSIBILITY_HCT_RECT_PROMPT_STATUS = - "accessibility_hct_rect_prompt_status"; + @Deprecated + public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = + Global.WIFI_NUM_OPEN_NETWORKS_KEPT; /** - * The color contrast, float in [-1, 1], 1 being the highest contrast. - * - * @hide + * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} + * instead. */ - public static final String CONTRAST_LEVEL = "contrast_level"; + @Deprecated + public static final String WIFI_ON = Global.WIFI_ON; /** - * Setting that specifies whether the display magnification is enabled via a system-wide - * triple tap gesture. Display magnifications allows the user to zoom in the display content - * and is targeted to low vision users. The current magnification scale is controlled by - * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. - * - * @hide + * The acceptable packet loss percentage (range 0 - 100) before trying + * another AP on the same network. + * @deprecated This setting is not used. */ - @UnsupportedAppUsage - @TestApi + @Deprecated @Readable - public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = - "accessibility_display_magnification_enabled"; + public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = + "wifi_watchdog_acceptable_packet_loss_percentage"; /** - * Setting that specifies whether the display magnification is enabled via a shortcut - * affordance within the system's navigation area. Display magnifications allows the user to - * zoom in the display content and is targeted to low vision users. The current - * magnification scale is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. - * - * @deprecated Use {@link #ACCESSIBILITY_BUTTON_TARGETS} instead. - * {@link #ACCESSIBILITY_BUTTON_TARGETS} holds the magnification system class name - * when navigation bar magnification is enabled. - * @hide + * The number of access points required for a network in order for the + * watchdog to monitor it. + * @deprecated This setting is not used. */ - @SystemApi + @Deprecated @Readable - public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = - "accessibility_display_magnification_navbar_enabled"; + public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count"; /** - * Setting that specifies what the display magnification scale is. - * Display magnifications allows the user to zoom in the display - * content and is targeted to low vision users. Whether a display - * magnification is performed is controlled by - * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED} and - * {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED} - * - * @hide + * The delay between background checks. + * @deprecated This setting is not used. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE = - "accessibility_display_magnification_scale"; + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = + "wifi_watchdog_background_check_delay_ms"; /** - * Unused mangnification setting - * - * @hide - * @deprecated + * Whether the Wi-Fi watchdog is enabled for background checking even + * after it thinks the user has connected to a good access point. + * @deprecated This setting is not used. */ @Deprecated @Readable - public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE = - "accessibility_display_magnification_auto_update"; + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = + "wifi_watchdog_background_check_enabled"; /** - * Accessibility Window Magnification Allow diagonal scrolling value. The value is boolean. - * 1 : on, 0 : off - * - * @hide + * The timeout for a background ping + * @deprecated This setting is not used. */ - public static final String ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING = - "accessibility_allow_diagonal_scrolling"; + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = + "wifi_watchdog_background_check_timeout_ms"; + /** + * The number of initial pings to perform that *may* be ignored if they + * fail. Again, if these fail, they will *not* be used in packet loss + * calculation. For example, one network always seemed to time out for + * the first couple pings, so this is set to 3 by default. + * @deprecated This setting is not used. + */ + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = + "wifi_watchdog_initial_ignored_ping_count"; /** - * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be - * modified from an AccessibilityService using the SoftKeyboardController. - * - * @hide + * The maximum number of access points (per network) to attempt to test. + * If this number is reached, the watchdog will no longer monitor the + * initial connection state for the network. This is a safeguard for + * networks containing multiple APs whose DNS does not respond to pings. + * @deprecated This setting is not used. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE = - "accessibility_soft_keyboard_mode"; + public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks"; /** - * Default soft keyboard behavior. - * - * @hide + * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead */ - public static final int SHOW_MODE_AUTO = 0; + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; /** - * Soft keyboard is never shown. - * - * @hide + * A comma-separated list of SSIDs for which the Wi-Fi watchdog should be enabled. + * @deprecated This setting is not used. */ - public static final int SHOW_MODE_HIDDEN = 1; + @Deprecated + @Readable + public static final String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list"; /** - * Setting that specifies whether timed text (captions) should be - * displayed in video content. Text display properties are controlled by - * the following settings: - *

    - *
  • {@link #ACCESSIBILITY_CAPTIONING_LOCALE} - *
  • {@link #ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR} - *
  • {@link #ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR} - *
  • {@link #ACCESSIBILITY_CAPTIONING_EDGE_COLOR} - *
  • {@link #ACCESSIBILITY_CAPTIONING_EDGE_TYPE} - *
  • {@link #ACCESSIBILITY_CAPTIONING_TYPEFACE} - *
  • {@link #ACCESSIBILITY_CAPTIONING_FONT_SCALE} - *
- * - * @hide + * The number of pings to test if an access point is a good connection. + * @deprecated This setting is not used. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_CAPTIONING_ENABLED = - "accessibility_captioning_enabled"; + public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count"; /** - * Setting that specifies the language for captions as a locale string, - * e.g. en_US. - * - * @see java.util.Locale#toString - * @hide + * The delay between pings. + * @deprecated This setting is not used. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_CAPTIONING_LOCALE = - "accessibility_captioning_locale"; + public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms"; /** - * Integer property that specifies the preset style for captions, one - * of: - *
    - *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESET_CUSTOM} - *
  • a valid index of {@link android.view.accessibility.CaptioningManager.CaptionStyle#PRESETS} - *
- * - * @see java.util.Locale#toString - * @hide + * The timeout per ping. + * @deprecated This setting is not used. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_CAPTIONING_PRESET = - "accessibility_captioning_preset"; + public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms"; /** - * Integer property that specifes the background color for captions as a - * packed 32-bit color. + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead + */ + @Deprecated + public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; + + /** + * @deprecated Use + * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + */ + @Deprecated + public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = + Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + + /** + * The number of milliseconds to hold on to a PendingIntent based request. This delay gives + * the receivers of the PendingIntent an opportunity to make a new network request before + * the Network satisfying the request is potentially removed. * - * @see android.graphics.Color#argb * @hide */ @Readable - public static final String ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR = - "accessibility_captioning_background_color"; + public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS = + "connectivity_release_pending_intent_delay_ms"; /** - * Integer property that specifes the foreground color for captions as a - * packed 32-bit color. + * Whether background data usage is allowed. * - * @see android.graphics.Color#argb - * @hide + * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, + * availability of background data depends on several + * combined factors. When background data is unavailable, + * {@link ConnectivityManager#getActiveNetworkInfo()} will + * now appear disconnected. */ + @Deprecated @Readable - public static final String ACCESSIBILITY_CAPTIONING_FOREGROUND_COLOR = - "accessibility_captioning_foreground_color"; + public static final String BACKGROUND_DATA = "background_data"; /** - * Integer property that specifes the edge type for captions, one of: - *
    - *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_NONE} - *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_OUTLINE} - *
  • {@link android.view.accessibility.CaptioningManager.CaptionStyle#EDGE_TYPE_DROP_SHADOW} - *
- * - * @see #ACCESSIBILITY_CAPTIONING_EDGE_COLOR - * @hide + * Origins for which browsers should allow geolocation by default. + * The value is a space-separated list of origins. */ @Readable - public static final String ACCESSIBILITY_CAPTIONING_EDGE_TYPE = - "accessibility_captioning_edge_type"; + public static final String ALLOWED_GEOLOCATION_ORIGINS + = "allowed_geolocation_origins"; /** - * Integer property that specifes the edge color for captions as a - * packed 32-bit color. - * - * @see #ACCESSIBILITY_CAPTIONING_EDGE_TYPE - * @see android.graphics.Color#argb + * The preferred TTY mode 0 = TTy Off, CDMA default + * 1 = TTY Full + * 2 = TTY HCO + * 3 = TTY VCO * @hide */ @Readable - public static final String ACCESSIBILITY_CAPTIONING_EDGE_COLOR = - "accessibility_captioning_edge_color"; + public static final String PREFERRED_TTY_MODE = + "preferred_tty_mode"; /** - * Integer property that specifes the window color for captions as a - * packed 32-bit color. - * - * @see android.graphics.Color#argb + * Whether the enhanced voice privacy mode is enabled. + * 0 = normal voice privacy + * 1 = enhanced voice privacy * @hide */ @Readable - public static final String ACCESSIBILITY_CAPTIONING_WINDOW_COLOR = - "accessibility_captioning_window_color"; + public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled"; /** - * String property that specifies the typeface for captions, one of: - *
    - *
  • DEFAULT - *
  • MONOSPACE - *
  • SANS_SERIF - *
  • SERIF - *
- * - * @see android.graphics.Typeface + * Whether the TTY mode mode is enabled. + * 0 = disabled + * 1 = enabled * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String ACCESSIBILITY_CAPTIONING_TYPEFACE = - "accessibility_captioning_typeface"; + public static final String TTY_MODE_ENABLED = "tty_mode_enabled"; /** - * Floating point property that specifies font scaling for captions. - * - * @hide + * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT + * calls when supported by the device and carrier. Boolean value. + * 0 = OFF + * 1 = ON */ @Readable - public static final String ACCESSIBILITY_CAPTIONING_FONT_SCALE = - "accessibility_captioning_font_scale"; + public static final String RTT_CALLING_MODE = "rtt_calling_mode"; /** - * Setting that specifies whether display color inversion is enabled. + /** + * Controls whether settings backup is enabled. + * Type: int ( 0 = disabled, 1 = enabled ) + * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = - "accessibility_display_inversion_enabled"; + public static final String BACKUP_ENABLED = "backup_enabled"; /** - * Flag that specifies whether font size has been changed. The flag will - * be set when users change the scaled value of font size for the first time. + * Controls whether application data is automatically restored from backup + * at install time. + * Type: int ( 0 = disabled, 1 = enabled ) * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED = - "accessibility_font_scaling_has_been_changed"; + public static final String BACKUP_AUTO_RESTORE = "backup_auto_restore"; /** - * Setting that specifies whether display color space adjustment is - * enabled. - * + * Controls whether framework backup scheduling is enabled. * @hide */ - @UnsupportedAppUsage - @Readable - public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED = - "accessibility_display_daltonizer_enabled"; + public static final String BACKUP_SCHEDULING_ENABLED = "backup_scheduling_enabled"; /** - * Integer property that specifies the type of color space adjustment to - * perform. Valid values are defined in AccessibilityManager and Settings arrays.xml: - * - AccessibilityManager.DALTONIZER_DISABLED = -1 - * - AccessibilityManager.DALTONIZER_SIMULATE_MONOCHROMACY = 0 - * - @string/daltonizer_mode_protanomaly = 11 - * - AccessibilityManager.DALTONIZER_CORRECT_DEUTERANOMALY and - * @string/daltonizer_mode_deuteranomaly = 12 - * - @string/daltonizer_mode_tritanomaly = 13 - * + * Indicates whether settings backup has been fully provisioned. + * Type: int ( 0 = unprovisioned, 1 = fully provisioned ) * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String ACCESSIBILITY_DISPLAY_DALTONIZER = - "accessibility_display_daltonizer"; + public static final String BACKUP_PROVISIONED = "backup_provisioned"; /** - * Integer property that determines the saturation level of color correction. Default value - * is defined in Settings config.xml. - * [0-10] inclusive where 0 would look as if color space adustment is not applied at all. - * + * Component of the transport to use for backup/restore. * @hide */ - public static final String ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL = - "accessibility_display_daltonizer_saturation_level"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @Readable + public static final String BACKUP_TRANSPORT = "backup_transport"; /** - * Setting that specifies whether automatic click when the mouse pointer stops moving is - * enabled. + * Indicates the version for which the setup wizard was last shown. The version gets + * bumped for each release when there is new setup information to show. * * @hide */ - @UnsupportedAppUsage + @SystemApi @Readable - public static final String ACCESSIBILITY_AUTOCLICK_ENABLED = - "accessibility_autoclick_enabled"; + public static final String LAST_SETUP_SHOWN = "last_setup_shown"; /** - * Integer setting specifying amount of time in ms the mouse pointer has to stay still - * before performing click when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. - * - * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * The interval in milliseconds after which Wi-Fi is considered idle. + * When idle, it is possible for the device to be switched from Wi-Fi to + * the mobile data network. * @hide + * @deprecated Use {@link android.provider.Settings.Global#WIFI_IDLE_MS} + * instead. */ - @Readable - public static final String ACCESSIBILITY_AUTOCLICK_DELAY = - "accessibility_autoclick_delay"; + @Deprecated + public static final String WIFI_IDLE_MS = Global.WIFI_IDLE_MS; /** - * Integer setting specifying the autoclick cursor area size (the radius of the autoclick - * ring indicator) when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. + * The global search provider chosen by the user (if multiple global + * search providers are installed). This will be the provider returned + * by {@link SearchManager#getGlobalSearchActivity()} if it's still + * installed. This setting is stored as a flattened component name as + * per {@link ComponentName#flattenToString()}. * - * @see #ACCESSIBILITY_AUTOCLICK_ENABLED * @hide */ - public static final String ACCESSIBILITY_AUTOCLICK_CURSOR_AREA_SIZE = - "accessibility_autoclick_cursor_area_size"; + @Readable + public static final String SEARCH_GLOBAL_SEARCH_ACTIVITY = + "search_global_search_activity"; /** - * Setting that specifies whether minor cursor movement will be ignored when - * {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. - * - * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * The number of promoted sources in GlobalSearch. * @hide */ - public static final String ACCESSIBILITY_AUTOCLICK_IGNORE_MINOR_CURSOR_MOVEMENT = - "accessibility_autoclick_ignore_minor_cursor_movement"; - + @Readable + public static final String SEARCH_NUM_PROMOTED_SOURCES = "search_num_promoted_sources"; /** - * String setting that stores the position of the autoclick panel when - * {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. The position is stored as a - * comma-separated string containing gravity, x-coordinate, y-coordinate, and corner index. - * For example, "8388659,15,30,0", where 8388659 means gravity Gravity.START | Gravity.TOP. - * - * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * The maximum number of suggestions returned by GlobalSearch. * @hide */ - public static final String ACCESSIBILITY_AUTOCLICK_PANEL_POSITION = - "accessibility_autoclick_panel_position"; - + @Readable + public static final String SEARCH_MAX_RESULTS_TO_DISPLAY = "search_max_results_to_display"; /** - * Setting that specifies whether autoclick type reverts to left click after performing - * an action when {@link #ACCESSIBILITY_AUTOCLICK_ENABLED} is set. - * - * @see #ACCESSIBILITY_AUTOCLICK_ENABLED + * The number of suggestions GlobalSearch will ask each non-web search source for. * @hide */ - public static final String ACCESSIBILITY_AUTOCLICK_REVERT_TO_LEFT_CLICK = - "accessibility_autoclick_revert_to_left_click"; - + @Readable + public static final String SEARCH_MAX_RESULTS_PER_SOURCE = "search_max_results_per_source"; /** - * Whether or not larger size icons are used for the pointer of mouse/trackpad for - * accessibility. - * (0 = false, 1 = true) - * - * @deprecated This setting is no longer in use, as the size of pointer icons is now - * controlled by the {@link #POINTER_SCALE} setting. The value of this setting - * is ignored. + * The number of suggestions the GlobalSearch will ask the web search source for. * @hide */ - @UnsupportedAppUsage @Readable - @Deprecated - public static final String ACCESSIBILITY_LARGE_POINTER_ICON = - "accessibility_large_pointer_icon"; - + public static final String SEARCH_WEB_RESULTS_OVERRIDE_LIMIT = + "search_web_results_override_limit"; /** - * The timeout for considering a press to be a long press in milliseconds. + * The number of milliseconds that GlobalSearch will wait for suggestions from + * promoted sources before continuing with all other sources. * @hide */ - @UnsupportedAppUsage @Readable - @TestApi - @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. - public static final String LONG_PRESS_TIMEOUT = "long_press_timeout"; - + public static final String SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS = + "search_promoted_source_deadline_millis"; /** - * The duration in milliseconds between the first tap's up event and the second tap's - * down event for an interaction to be considered part of the same multi-press. + * The number of milliseconds before GlobalSearch aborts search suggesiton queries. * @hide */ @Readable - @TestApi - @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. - public static final String MULTI_PRESS_TIMEOUT = "multi_press_timeout"; - + public static final String SEARCH_SOURCE_TIMEOUT_MILLIS = "search_source_timeout_millis"; /** - * Whether to enable key repeats for Physical Keyboard. - * - * If set to false, continuous key presses on - * physical keyboard will not cause the pressed key to repeated. + * The maximum number of milliseconds that GlobalSearch shows the previous results + * after receiving a new query. * @hide */ @Readable - public static final String KEY_REPEAT_ENABLED = "key_repeat_enabled"; - + public static final String SEARCH_PREFILL_MILLIS = "search_prefill_millis"; /** - * The duration before a key repeat begins in milliseconds. + * The maximum age of log data used for shortcuts in GlobalSearch. * @hide */ @Readable - public static final String KEY_REPEAT_TIMEOUT_MS = "key_repeat_timeout"; - + public static final String SEARCH_MAX_STAT_AGE_MILLIS = "search_max_stat_age_millis"; /** - * The duration between successive key repeats in milliseconds. + * The maximum age of log data used for source ranking in GlobalSearch. * @hide */ @Readable - public static final String KEY_REPEAT_DELAY_MS = "key_repeat_delay"; - + public static final String SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS = + "search_max_source_event_age_millis"; /** - * Setting that specifies recommended timeout in milliseconds for controls - * which don't need user's interactions. - * + * The minimum number of impressions needed to rank a source in GlobalSearch. * @hide */ @Readable - public static final String ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS = - "accessibility_non_interactive_ui_timeout_ms"; - + public static final String SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING = + "search_min_impressions_for_source_ranking"; /** - * Setting that specifies recommended timeout in milliseconds for controls - * which need user's interactions. - * + * The minimum number of clicks needed to rank a source in GlobalSearch. * @hide */ @Readable - public static final String ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS = - "accessibility_interactive_ui_timeout_ms"; - - + public static final String SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING = + "search_min_clicks_for_source_ranking"; /** - * Setting that specifies whether Reduce Bright Colors, or brightness dimming by color - * adjustment, is enabled. - * + * The maximum number of shortcuts shown by GlobalSearch. * @hide */ - public static final String REDUCE_BRIGHT_COLORS_ACTIVATED = - "reduce_bright_colors_activated"; - + @Readable + public static final String SEARCH_MAX_SHORTCUTS_RETURNED = "search_max_shortcuts_returned"; /** - * Setting that specifies the level of Reduce Bright Colors in intensity. The range is - * [0, 100]. - * + * The size of the core thread pool for suggestion queries in GlobalSearch. * @hide */ - public static final String REDUCE_BRIGHT_COLORS_LEVEL = - "reduce_bright_colors_level"; - + @Readable + public static final String SEARCH_QUERY_THREAD_CORE_POOL_SIZE = + "search_query_thread_core_pool_size"; /** - * Setting that specifies whether Reduce Bright Colors should persist across reboots. - * + * The maximum size of the thread pool for suggestion queries in GlobalSearch. * @hide */ - public static final String REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS = - "reduce_bright_colors_persist_across_reboots"; - + @Readable + public static final String SEARCH_QUERY_THREAD_MAX_POOL_SIZE = + "search_query_thread_max_pool_size"; /** - * Integer setting that specifies the duration in ms required to invert the text cursor's - * pixels. - * - * @see ViewConfiguration#getTextCursorBlinkIntervalMillis() - * + * The size of the core thread pool for shortcut refreshing in GlobalSearch. * @hide */ - public static final String ACCESSIBILITY_TEXT_CURSOR_BLINK_INTERVAL_MS = - "accessibility_text_cursor_blink_interval_ms"; - + @Readable + public static final String SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE = + "search_shortcut_refresh_core_pool_size"; /** - * Setting that holds EM_VALUE (proprietary) - * + * The maximum size of the thread pool for shortcut refreshing in GlobalSearch. * @hide */ - public static final String EM_VALUE = - "em_value"; + @Readable + public static final String SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE = + "search_shortcut_refresh_max_pool_size"; /** - * Setting that specifies whether High Dynamic Range brightness is enabled. - * + * The maximun time that excess threads in the GlobalSeach thread pools will + * wait before terminating. * @hide */ - public static final String HDR_BRIGHTNESS_ENABLED = - "hdr_brightness_enabled"; - + @Readable + public static final String SEARCH_THREAD_KEEPALIVE_SECONDS = + "search_thread_keepalive_seconds"; /** - * Setting that specifies the intensity of the High Dynamic Range brightness. The range is - * [0, 1], which is which is used to scale the HDR/SDR ratio. - * + * The maximum number of concurrent suggestion queries to each source. * @hide */ - public static final String HDR_BRIGHTNESS_BOOST_LEVEL = - "hdr_brightness_boost_level"; + @Readable + public static final String SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT = + "search_per_source_concurrent_query_limit"; /** - * List of the enabled print services. - * - * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade - * from pre-N. - * + * Whether or not alert sounds are played on StorageManagerService events. + * (0 = false, 1 = true) * @hide */ - @UnsupportedAppUsage @Readable - public static final String ENABLED_PRINT_SERVICES = - "enabled_print_services"; + public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd"; /** - * List of the disabled print services. - * + * Whether or not UMS auto-starts on UMS host detection. (0 = false, 1 = true) * @hide */ - @TestApi @Readable - public static final String DISABLED_PRINT_SERVICES = - "disabled_print_services"; + public static final String MOUNT_UMS_AUTOSTART = "mount_ums_autostart"; /** - * The saved value for WindowManagerService.setForcedDisplayDensity() - * formatted as a single integer representing DPI. If unset, then use - * the real display density. - * + * Whether or not a notification is displayed on UMS host detection. (0 = false, 1 = true) * @hide */ @Readable - public static final String DISPLAY_DENSITY_FORCED = "display_density_forced"; + public static final String MOUNT_UMS_PROMPT = "mount_ums_prompt"; /** - * Setting to always use the default text-to-speech settings regardless - * of the application settings. - * 1 = override application settings, - * 0 = use application settings (if specified). - * - * @deprecated The value of this setting is no longer respected by - * the framework text to speech APIs as of the Ice Cream Sandwich release. + * Whether or not a notification is displayed while UMS is enabled. (0 = false, 1 = true) + * @hide */ - @Deprecated @Readable - public static final String TTS_USE_DEFAULTS = "tts_use_defaults"; + public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled"; /** - * Default text-to-speech engine speech rate. 100 = 1x + * If nonzero, ANRs in invisible background processes bring up a dialog. + * Otherwise, the process will be silently killed. + * + * Also prevents ANRs and crash dialogs from being suppressed. + * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi @Readable - public static final String TTS_DEFAULT_RATE = "tts_default_rate"; + @SuppressLint("NoSettingsProvider") + public static final String ANR_SHOW_BACKGROUND = "anr_show_background"; /** - * Default text-to-speech engine pitch. 100 = 1x + * If nonzero, crashes in foreground processes will bring up a dialog. + * Otherwise, the process will be silently killed. + * @hide */ + @TestApi @Readable - public static final String TTS_DEFAULT_PITCH = "tts_default_pitch"; + @SuppressLint("NoSettingsProvider") + public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = + "show_first_crash_dialog_dev_option"; /** - * Default text-to-speech engine. + * The {@link ComponentName} string of the service to be used as the voice recognition + * service. + * + * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String TTS_DEFAULT_SYNTH = "tts_default_synth"; + public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service"; /** - * Default text-to-speech language. + * The {@link ComponentName} string of the selected spell checker service which is + * one of the services managed by the text service manager. * - * @deprecated this setting is no longer in use, as of the Ice Cream - * Sandwich release. Apps should never need to read this setting directly, - * instead can query the TextToSpeech framework classes for the default - * locale. {@link TextToSpeech#getLanguage()}. + * @hide */ - @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi @Readable - public static final String TTS_DEFAULT_LANG = "tts_default_lang"; + @SuppressLint("NoSettingsProvider") + public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker"; /** - * Default text-to-speech country. + * {@link android.view.textservice.SpellCheckerSubtype#hashCode()} of the selected subtype + * of the selected spell checker service which is one of the services managed by the text + * service manager. * - * @deprecated this setting is no longer in use, as of the Ice Cream - * Sandwich release. Apps should never need to read this setting directly, - * instead can query the TextToSpeech framework classes for the default - * locale. {@link TextToSpeech#getLanguage()}. + * @hide */ - @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi @Readable - public static final String TTS_DEFAULT_COUNTRY = "tts_default_country"; + @SuppressLint("NoSettingsProvider") + public static final String SELECTED_SPELL_CHECKER_SUBTYPE = + "selected_spell_checker_subtype"; /** - * Default text-to-speech locale variant. + * Whether spell checker is enabled or not. * - * @deprecated this setting is no longer in use, as of the Ice Cream - * Sandwich release. Apps should never need to read this setting directly, - * instead can query the TextToSpeech framework classes for the - * locale that is in use {@link TextToSpeech#getLanguage()}. + * @hide */ - @Deprecated @Readable - public static final String TTS_DEFAULT_VARIANT = "tts_default_variant"; + public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled"; /** - * Stores the default tts locales on a per engine basis. Stored as - * a comma seperated list of values, each value being of the form - * {@code engine_name:locale} for example, - * {@code com.foo.ttsengine:eng-USA,com.bar.ttsengine:esp-ESP}. This - * supersedes {@link #TTS_DEFAULT_LANG}, {@link #TTS_DEFAULT_COUNTRY} and - * {@link #TTS_DEFAULT_VARIANT}. Apps should never need to read this - * setting directly, and can query the TextToSpeech framework classes - * for the locale that is in use. + * What happens when the user presses the Power button while in-call + * and the screen is on.
+ * Values:
+ * 1 - The Power button turns off the screen and locks the device. (Default behavior)
+ * 2 - The Power button hangs up the current call.
* * @hide */ + @UnsupportedAppUsage @Readable - public static final String TTS_DEFAULT_LOCALE = "tts_default_locale"; + public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior"; /** - * Space delimited list of plugin packages that are enabled. + * Whether the user allows minimal post processing or not. + * + *

Values: + * 0 - Not allowed. Any preferences set through the Window.setPreferMinimalPostProcessing + * API will be ignored. + * 1 - Allowed. Any preferences set through the Window.setPreferMinimalPostProcessing API + * will be respected and the appropriate signals will be sent to display. + * (Default behaviour) + * + * @hide */ @Readable - public static final String TTS_ENABLED_PLUGINS = "tts_enabled_plugins"; + public static final String MINIMAL_POST_PROCESSING_ALLOWED = + "minimal_post_processing_allowed"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON} - * instead. + * Whether to mirror the built-in display on all connected displays. + * @hide */ - @Deprecated - public static final String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = - Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON; + @TestApi + @Readable + @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. + public static final String MIRROR_BUILT_IN_DISPLAY = "mirror_built_in_display"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY} - * instead. + * Whether to include the default display in the display topology. + * + * Note that this value is used for projected mode. + * @hide */ - @Deprecated - public static final String WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY = - Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY; + public static final String INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY = + "include_default_display_in_topology"; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_NUM_OPEN_NETWORKS_KEPT} - * instead. + * No mode switching will happen. + * + * @see #MATCH_CONTENT_FRAME_RATE + * @hide */ - @Deprecated - public static final String WIFI_NUM_OPEN_NETWORKS_KEPT = - Global.WIFI_NUM_OPEN_NETWORKS_KEPT; + public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_ON} - * instead. + * Allow only refresh rate switching between modes in the same configuration group. + * This way only switches without visual interruptions for the user will be allowed. + * + * @see #MATCH_CONTENT_FRAME_RATE + * @hide */ - @Deprecated - public static final String WIFI_ON = Global.WIFI_ON; + public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; /** - * The acceptable packet loss percentage (range 0 - 100) before trying - * another AP on the same network. - * @deprecated This setting is not used. - */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE = - "wifi_watchdog_acceptable_packet_loss_percentage"; + * Allow refresh rate switching between all refresh rates even if the switch will have + * visual interruptions for the user. + * + * @see #MATCH_CONTENT_FRAME_RATE + * @hide + */ + public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; /** - * The number of access points required for a network in order for the - * watchdog to monitor it. - * @deprecated This setting is not used. + * User's preference for refresh rate switching. + * + *

Values: + * 0 - Never switch refresh rates. + * 1 - Switch refresh rates only when it can be done seamlessly. (Default behaviour) + * 2 - Always prefer refresh rate switching even if it's going to have visual interruptions + * for the user. + * + * @see android.view.Surface#setFrameRate + * @see #MATCH_CONTENT_FRAMERATE_NEVER + * @see #MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY + * @see #MATCH_CONTENT_FRAMERATE_ALWAYS + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_AP_COUNT = "wifi_watchdog_ap_count"; + public static final String MATCH_CONTENT_FRAME_RATE = + "match_content_frame_rate"; /** - * The delay between background checks. - * @deprecated This setting is not used. + * INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen". + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS = - "wifi_watchdog_background_check_delay_ms"; + public static final int INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF = 0x1; /** - * Whether the Wi-Fi watchdog is enabled for background checking even - * after it thinks the user has connected to a good access point. - * @deprecated This setting is not used. + * INCALL_POWER_BUTTON_BEHAVIOR value for "hang up". + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED = - "wifi_watchdog_background_check_enabled"; + public static final int INCALL_POWER_BUTTON_BEHAVIOR_HANGUP = 0x2; /** - * The timeout for a background ping - * @deprecated This setting is not used. + * INCALL_POWER_BUTTON_BEHAVIOR default value. + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS = - "wifi_watchdog_background_check_timeout_ms"; + public static final int INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT = + INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF; /** - * The number of initial pings to perform that *may* be ignored if they - * fail. Again, if these fail, they will *not* be used in packet loss - * calculation. For example, one network always seemed to time out for - * the first couple pings, so this is set to 3 by default. - * @deprecated This setting is not used. + * What happens when the user presses the Back button while in-call + * and the screen is on.
+ * Values:
+ * 0 - The Back buttons does nothing different.
+ * 1 - The Back button hangs up the current call.
+ * + * @hide */ - @Deprecated @Readable - public static final String WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT = - "wifi_watchdog_initial_ignored_ping_count"; + public static final String INCALL_BACK_BUTTON_BEHAVIOR = "incall_back_button_behavior"; /** - * The maximum number of access points (per network) to attempt to test. - * If this number is reached, the watchdog will no longer monitor the - * initial connection state for the network. This is a safeguard for - * networks containing multiple APs whose DNS does not respond to pings. - * @deprecated This setting is not used. + * INCALL_BACK_BUTTON_BEHAVIOR value for no action. + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_MAX_AP_CHECKS = "wifi_watchdog_max_ap_checks"; + public static final int INCALL_BACK_BUTTON_BEHAVIOR_NONE = 0x0; /** - * @deprecated Use {@link android.provider.Settings.Global#WIFI_WATCHDOG_ON} instead + * INCALL_BACK_BUTTON_BEHAVIOR value for "hang up". + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_ON = "wifi_watchdog_on"; + public static final int INCALL_BACK_BUTTON_BEHAVIOR_HANGUP = 0x1; /** - * A comma-separated list of SSIDs for which the Wi-Fi watchdog should be enabled. - * @deprecated This setting is not used. + * INCALL_POWER_BUTTON_BEHAVIOR default value. + * @hide */ - @Deprecated - @Readable - public static final String WIFI_WATCHDOG_WATCH_LIST = "wifi_watchdog_watch_list"; + public static final int INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT = + INCALL_BACK_BUTTON_BEHAVIOR_NONE; /** - * The number of pings to test if an access point is a good connection. - * @deprecated This setting is not used. + * Whether the device should wake when the wake gesture sensor detects motion. + * @hide */ - @Deprecated @Readable - public static final String WIFI_WATCHDOG_PING_COUNT = "wifi_watchdog_ping_count"; + public static final String WAKE_GESTURE_ENABLED = "wake_gesture_enabled"; /** - * The delay between pings. - * @deprecated This setting is not used. + * Whether the device should doze if configured. + * @hide */ - @Deprecated + @UnsupportedAppUsage @Readable - public static final String WIFI_WATCHDOG_PING_DELAY_MS = "wifi_watchdog_ping_delay_ms"; + public static final String DOZE_ENABLED = "doze_enabled"; /** - * The timeout per ping. - * @deprecated This setting is not used. + * Indicates whether doze should be always on. + *

+ * Type: int (0 for false, 1 for true) + * + * @hide */ - @Deprecated + @SystemApi @Readable - public static final String WIFI_WATCHDOG_PING_TIMEOUT_MS = "wifi_watchdog_ping_timeout_ms"; + public static final String DOZE_ALWAYS_ON = "doze_always_on"; /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_MAX_DHCP_RETRY_COUNT} instead + * Indicates whether doze turns on automatically + * 0 = disabled (default) + * 1 = from sunset to sunrise + * 2 = custom time + * 3 = from sunset till a time + * 4 = from a time till sunrise + * @hide */ - @Deprecated - public static final String WIFI_MAX_DHCP_RETRY_COUNT = Global.WIFI_MAX_DHCP_RETRY_COUNT; + @Readable + public static final String DOZE_ALWAYS_ON_AUTO_MODE = "doze_always_on_auto_mode"; /** - * @deprecated Use - * {@link android.provider.Settings.Global#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS} instead + * The custom time {@link DOZE_ALWAYS_ON} should be on at + * Only relevant when {@link DOZE_ALWAYS_ON_AUTO_MODE} is set to 2 and above + * 0 = Disabled (default) + * format: HH:mm,HH:mm (since,till) + * @hide */ - @Deprecated - public static final String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = - Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; + @Readable + public static final String DOZE_ALWAYS_ON_AUTO_TIME = "doze_always_on_auto_time"; /** - * The number of milliseconds to hold on to a PendingIntent based request. This delay gives - * the receivers of the PendingIntent an opportunity to make a new network request before - * the Network satisfying the request is potentially removed. + * Indicates whether doze should briefly show AOD when the screen turns off. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ @Readable - public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS = - "connectivity_release_pending_intent_delay_ms"; + public static final String DOZE_PEEK = "doze_peek"; /** - * Whether background data usage is allowed. + * Indicates how long doze peek should stay visible when the screen turns off. + *

+ * Type: int (seconds) * - * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, - * availability of background data depends on several - * combined factors. When background data is unavailable, - * {@link ConnectivityManager#getActiveNetworkInfo()} will - * now appear disconnected. + * @hide */ - @Deprecated @Readable - public static final String BACKGROUND_DATA = "background_data"; + public static final String DOZE_PEEK_DURATION = "doze_peek_duration"; /** - * Origins for which browsers should allow geolocation by default. - * The value is a space-separated list of origins. + * Indicates whether ambient wallpaper is visible with AOD. + *

+ * Type: int (0 for false, 1 for true) + * + * @hide */ - @Readable - public static final String ALLOWED_GEOLOCATION_ORIGINS - = "allowed_geolocation_origins"; + public static final String DOZE_ALWAYS_ON_WALLPAPER_ENABLED = + "doze_always_on_wallpaper_enabled"; /** - * The preferred TTY mode 0 = TTy Off, CDMA default - * 1 = TTY Full - * 2 = TTY HCO - * 3 = TTY VCO + * Whether the device should pulse on pick up gesture. * @hide */ @Readable - public static final String PREFERRED_TTY_MODE = - "preferred_tty_mode"; + public static final String DOZE_PICK_UP_GESTURE = "doze_pick_up_gesture"; /** - * Whether the enhanced voice privacy mode is enabled. - * 0 = normal voice privacy - * 1 = enhanced voice privacy + * Whether the device should pulse on long press gesture. * @hide */ @Readable - public static final String ENHANCED_VOICE_PRIVACY_ENABLED = "enhanced_voice_privacy_enabled"; + public static final String DOZE_PULSE_ON_LONG_PRESS = "doze_pulse_on_long_press"; /** - * Whether the TTY mode mode is enabled. - * 0 = disabled - * 1 = enabled + * Whether the device should pulse on double tap gesture. * @hide */ @Readable - public static final String TTY_MODE_ENABLED = "tty_mode_enabled"; + public static final String DOZE_DOUBLE_TAP_GESTURE = "doze_pulse_on_double_tap"; /** - * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT - * calls when supported by the device and carrier. Boolean value. - * 0 = OFF - * 1 = ON + * Whether the device should respond to the SLPI tap gesture. + * @hide */ @Readable - public static final String RTT_CALLING_MODE = "rtt_calling_mode"; + public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture"; /** - /** - * Controls whether settings backup is enabled. - * Type: int ( 0 = disabled, 1 = enabled ) + * Gesture that wakes up the display, showing some version of the lock screen. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String BACKUP_ENABLED = "backup_enabled"; + public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_screen_gesture"; /** - * Controls whether application data is automatically restored from backup - * at install time. - * Type: int ( 0 = disabled, 1 = enabled ) + * Gesture that wakes up the display, toggling between {@link Display.STATE_OFF} and + * {@link Display.STATE_DOZE}. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String BACKUP_AUTO_RESTORE = "backup_auto_restore"; + public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture"; /** - * Controls whether framework backup scheduling is enabled. + * Gesture that wakes up the display on quick pickup, toggling between + * {@link Display.STATE_OFF} and {@link Display.STATE_DOZE}. * @hide */ - public static final String BACKUP_SCHEDULING_ENABLED = "backup_scheduling_enabled"; + public static final String DOZE_QUICK_PICKUP_GESTURE = "doze_quick_pickup_gesture"; /** - * Indicates whether settings backup has been fully provisioned. - * Type: int ( 0 = unprovisioned, 1 = fully provisioned ) + * Whether the device should suppress the current doze configuration and disable dozing. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String BACKUP_PROVISIONED = "backup_provisioned"; + public static final String SUPPRESS_DOZE = "suppress_doze"; /** - * Component of the transport to use for backup/restore. + * Pulse notifications on tilt * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Readable - public static final String BACKUP_TRANSPORT = "backup_transport"; + public static final String DOZE_TILT_GESTURE = "doze_tilt_gesture"; /** - * Indicates the version for which the setup wizard was last shown. The version gets - * bumped for each release when there is new setup information to show. - * + * Pulse notifications on hand wave * @hide */ - @SystemApi - @Readable - public static final String LAST_SETUP_SHOWN = "last_setup_shown"; + public static final String DOZE_HANDWAVE_GESTURE = "doze_handwave_gesture"; /** - * The interval in milliseconds after which Wi-Fi is considered idle. - * When idle, it is possible for the device to be switched from Wi-Fi to - * the mobile data network. + * Pulse notifications on removal from pocket * @hide - * @deprecated Use {@link android.provider.Settings.Global#WIFI_IDLE_MS} - * instead. */ - @Deprecated - public static final String WIFI_IDLE_MS = Global.WIFI_IDLE_MS; + public static final String DOZE_POCKET_GESTURE = "doze_pocket_gesture"; /** - * The global search provider chosen by the user (if multiple global - * search providers are installed). This will be the provider returned - * by {@link SearchManager#getGlobalSearchActivity()} if it's still - * installed. This setting is stored as a flattened component name as - * per {@link ComponentName#flattenToString()}. - * + * Wake up instead of pulsing notifications * @hide */ - @Readable - public static final String SEARCH_GLOBAL_SEARCH_ACTIVITY = - "search_global_search_activity"; + public static final String RAISE_TO_WAKE_GESTURE = "raise_to_wake_gesture"; /** - * The number of promoted sources in GlobalSearch. + * Vibrate when pulsing notifications on gesture * @hide */ - @Readable - public static final String SEARCH_NUM_PROMOTED_SOURCES = "search_num_promoted_sources"; + public static final String DOZE_GESTURE_VIBRATE = "doze_gesture_vibrate"; + /** - * The maximum number of suggestions returned by GlobalSearch. + * Gesture that skips media. * @hide */ @Readable - public static final String SEARCH_MAX_RESULTS_TO_DISPLAY = "search_max_results_to_display"; + public static final String SKIP_GESTURE = "skip_gesture"; + /** - * The number of suggestions GlobalSearch will ask each non-web search source for. + * Count of successful gestures. * @hide */ @Readable - public static final String SEARCH_MAX_RESULTS_PER_SOURCE = "search_max_results_per_source"; + public static final String SKIP_GESTURE_COUNT = "skip_gesture_count"; + /** - * The number of suggestions the GlobalSearch will ask the web search source for. + * Count of non-gesture interaction. * @hide */ @Readable - public static final String SEARCH_WEB_RESULTS_OVERRIDE_LIMIT = - "search_web_results_override_limit"; + public static final String SKIP_TOUCH_COUNT = "skip_touch_count"; + /** - * The number of milliseconds that GlobalSearch will wait for suggestions from - * promoted sources before continuing with all other sources. + * Direction to advance media for skip gesture * @hide */ @Readable - public static final String SEARCH_PROMOTED_SOURCE_DEADLINE_MILLIS = - "search_promoted_source_deadline_millis"; + public static final String SKIP_DIRECTION = "skip_gesture_direction"; + /** - * The number of milliseconds before GlobalSearch aborts search suggesiton queries. + * Gesture that silences sound (alarms, notification, calls). * @hide */ @Readable - public static final String SEARCH_SOURCE_TIMEOUT_MILLIS = "search_source_timeout_millis"; + public static final String SILENCE_GESTURE = "silence_gesture"; + /** - * The maximum number of milliseconds that GlobalSearch shows the previous results - * after receiving a new query. + * Count of successful silence alarms gestures. * @hide */ @Readable - public static final String SEARCH_PREFILL_MILLIS = "search_prefill_millis"; + public static final String SILENCE_ALARMS_GESTURE_COUNT = "silence_alarms_gesture_count"; + /** - * The maximum age of log data used for shortcuts in GlobalSearch. + * Count of successful silence timer gestures. * @hide */ @Readable - public static final String SEARCH_MAX_STAT_AGE_MILLIS = "search_max_stat_age_millis"; + public static final String SILENCE_TIMER_GESTURE_COUNT = "silence_timer_gesture_count"; + /** - * The maximum age of log data used for source ranking in GlobalSearch. + * Count of successful silence call gestures. * @hide */ @Readable - public static final String SEARCH_MAX_SOURCE_EVENT_AGE_MILLIS = - "search_max_source_event_age_millis"; + public static final String SILENCE_CALL_GESTURE_COUNT = "silence_call_gesture_count"; + /** - * The minimum number of impressions needed to rank a source in GlobalSearch. + * Count of non-gesture interaction. * @hide */ @Readable - public static final String SEARCH_MIN_IMPRESSIONS_FOR_SOURCE_RANKING = - "search_min_impressions_for_source_ranking"; + public static final String SILENCE_ALARMS_TOUCH_COUNT = "silence_alarms_touch_count"; + /** - * The minimum number of clicks needed to rank a source in GlobalSearch. + * Count of non-gesture interaction. * @hide */ @Readable - public static final String SEARCH_MIN_CLICKS_FOR_SOURCE_RANKING = - "search_min_clicks_for_source_ranking"; + public static final String SILENCE_TIMER_TOUCH_COUNT = "silence_timer_touch_count"; + /** - * The maximum number of shortcuts shown by GlobalSearch. + * Count of non-gesture interaction. * @hide */ @Readable - public static final String SEARCH_MAX_SHORTCUTS_RETURNED = "search_max_shortcuts_returned"; + public static final String SILENCE_CALL_TOUCH_COUNT = "silence_call_touch_count"; + /** - * The size of the core thread pool for suggestion queries in GlobalSearch. + * Number of successful "Motion Sense" tap gestures to pause media. * @hide */ @Readable - public static final String SEARCH_QUERY_THREAD_CORE_POOL_SIZE = - "search_query_thread_core_pool_size"; + public static final String AWARE_TAP_PAUSE_GESTURE_COUNT = "aware_tap_pause_gesture_count"; + /** - * The maximum size of the thread pool for suggestion queries in GlobalSearch. + * Number of touch interactions to pause media when a "Motion Sense" gesture could + * have been used. * @hide */ @Readable - public static final String SEARCH_QUERY_THREAD_MAX_POOL_SIZE = - "search_query_thread_max_pool_size"; + public static final String AWARE_TAP_PAUSE_TOUCH_COUNT = "aware_tap_pause_touch_count"; + /** - * The size of the core thread pool for shortcut refreshing in GlobalSearch. + * For user preference if swipe bottom to expand notification gesture enabled. * @hide */ - @Readable - public static final String SEARCH_SHORTCUT_REFRESH_CORE_POOL_SIZE = - "search_shortcut_refresh_core_pool_size"; + public static final String SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED = + "swipe_bottom_to_notification_enabled"; + /** - * The maximum size of the thread pool for shortcut refreshing in GlobalSearch. + * Controls whether One-Handed mode is currently activated. * @hide */ - @Readable - public static final String SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE = - "search_shortcut_refresh_max_pool_size"; + public static final String ONE_HANDED_MODE_ACTIVATED = "one_handed_mode_activated"; + /** - * The maximun time that excess threads in the GlobalSeach thread pools will - * wait before terminating. + * For user preference if One-Handed Mode enabled. * @hide */ - @Readable - public static final String SEARCH_THREAD_KEEPALIVE_SECONDS = - "search_thread_keepalive_seconds"; + public static final String ONE_HANDED_MODE_ENABLED = "one_handed_mode_enabled"; + /** - * The maximum number of concurrent suggestion queries to each source. + * For user preference if One-Handed Mode timeout. * @hide */ - @Readable - public static final String SEARCH_PER_SOURCE_CONCURRENT_QUERY_LIMIT = - "search_per_source_concurrent_query_limit"; + public static final String ONE_HANDED_MODE_TIMEOUT = "one_handed_mode_timeout"; /** - * Whether or not alert sounds are played on StorageManagerService events. - * (0 = false, 1 = true) + * For user taps app to exit One-Handed Mode. * @hide */ - @Readable - public static final String MOUNT_PLAY_NOTIFICATION_SND = "mount_play_not_snd"; + public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit"; /** - * Whether or not UMS auto-starts on UMS host detection. (0 = false, 1 = true) + * Internal use, one handed mode tutorial showed times. * @hide */ - @Readable - public static final String MOUNT_UMS_AUTOSTART = "mount_ums_autostart"; + public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT = + "one_handed_tutorial_show_count"; /** - * Whether or not a notification is displayed on UMS host detection. (0 = false, 1 = true) + * Toggle to enable/disable for the apps to use the Ui translation for Views. The value + * indicates whether the Ui translation is enabled by the user. + *

+ * Type: {@code int} ({@code 0} for disabled, {@code 1} for enabled) + * * @hide */ + @SystemApi @Readable - public static final String MOUNT_UMS_PROMPT = "mount_ums_prompt"; + @SuppressLint("NoSettingsProvider") + public static final String UI_TRANSLATION_ENABLED = "ui_translation_enabled"; /** - * Whether or not a notification is displayed while UMS is enabled. (0 = false, 1 = true) + * The current night mode that has been selected by the user. Owned + * and controlled by UiModeManagerService. Constants are as per + * UiModeManager. * @hide */ @Readable - public static final String MOUNT_UMS_NOTIFY_ENABLED = "mount_ums_notify_enabled"; + public static final String UI_NIGHT_MODE = "ui_night_mode"; /** - * If nonzero, ANRs in invisible background processes bring up a dialog. - * Otherwise, the process will be silently killed. - * - * Also prevents ANRs and crash dialogs from being suppressed. + * The current night mode custom type that has been selected by the user. Owned + * and controlled by UiModeManagerService. Constants are as per UiModeManager. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi @Readable @SuppressLint("NoSettingsProvider") - public static final String ANR_SHOW_BACKGROUND = "anr_show_background"; + public static final String UI_NIGHT_MODE_CUSTOM_TYPE = "ui_night_mode_custom_type"; /** - * If nonzero, crashes in foreground processes will bring up a dialog. - * Otherwise, the process will be silently killed. + * The current night mode that has been overridden to turn on by the system. Owned + * and controlled by UiModeManagerService. Constants are as per + * UiModeManager. * @hide */ - @TestApi @Readable - @SuppressLint("NoSettingsProvider") - public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION = - "show_first_crash_dialog_dev_option"; + public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on"; /** - * The {@link ComponentName} string of the service to be used as the voice recognition - * service. - * + * The last computed night mode bool the last time the phone was on * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @Readable - public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service"; + public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed"; /** - * The {@link ComponentName} string of the selected spell checker service which is - * one of the services managed by the text service manager. - * + * The current night mode that has been overridden to turn off by the system. Owned + * and controlled by UiModeManagerService. Constants are as per + * UiModeManager. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi @Readable - @SuppressLint("NoSettingsProvider") - public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker"; + public static final String UI_NIGHT_MODE_OVERRIDE_OFF = "ui_night_mode_override_off"; /** - * {@link android.view.textservice.SpellCheckerSubtype#hashCode()} of the selected subtype - * of the selected spell checker service which is one of the services managed by the text - * service manager. - * + * Whether screensavers are enabled. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi @Readable - @SuppressLint("NoSettingsProvider") - public static final String SELECTED_SPELL_CHECKER_SUBTYPE = - "selected_spell_checker_subtype"; + public static final String SCREENSAVER_ENABLED = "screensaver_enabled"; /** - * Whether spell checker is enabled or not. + * The user's chosen screensaver components. * + * These will be launched by the PhoneWindowManager after a timeout when not on + * battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1). * @hide */ @Readable - public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled"; + public static final String SCREENSAVER_COMPONENTS = "screensaver_components"; /** - * What happens when the user presses the Power button while in-call - * and the screen is on.
- * Values:
- * 1 - The Power button turns off the screen and locks the device. (Default behavior)
- * 2 - The Power button hangs up the current call.
- * + * If screensavers are enabled, whether the screensaver should be automatically launched + * when the device is inserted into a (desk) dock. * @hide */ - @UnsupportedAppUsage @Readable - public static final String INCALL_POWER_BUTTON_BEHAVIOR = "incall_power_button_behavior"; + public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock"; /** - * Whether the user allows minimal post processing or not. - * - *

Values: - * 0 - Not allowed. Any preferences set through the Window.setPreferMinimalPostProcessing - * API will be ignored. - * 1 - Allowed. Any preferences set through the Window.setPreferMinimalPostProcessing API - * will be respected and the appropriate signals will be sent to display. - * (Default behaviour) - * + * If screensavers are enabled, whether the screensaver should be automatically launched + * when the screen times out when not on battery. * @hide */ @Readable - public static final String MINIMAL_POST_PROCESSING_ALLOWED = - "minimal_post_processing_allowed"; + public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep"; /** - * Whether to mirror the built-in display on all connected displays. + * If screensavers are enabled, whether the screensaver should be + * automatically launched when the device is stationary and upright. * @hide */ - @TestApi @Readable - @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. - public static final String MIRROR_BUILT_IN_DISPLAY = "mirror_built_in_display"; + public static final String SCREENSAVER_ACTIVATE_ON_POSTURED = + "screensaver_activate_on_postured"; /** - * Whether to include the default display in the display topology. - * - * Note that this value is used for projected mode. + * If screensavers are enabled, the default screensaver component. * @hide */ - public static final String INCLUDE_DEFAULT_DISPLAY_IN_TOPOLOGY = - "include_default_display_in_topology"; + @Readable + public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component"; /** - * No mode switching will happen. + * Whether complications are enabled to be shown over the screensaver by the user. * - * @see #MATCH_CONTENT_FRAME_RATE * @hide */ - public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; + public static final String SCREENSAVER_COMPLICATIONS_ENABLED = + "screensaver_complications_enabled"; /** - * Allow only refresh rate switching between modes in the same configuration group. - * This way only switches without visual interruptions for the user will be allowed. + * Defines the enabled state for the glanceable hub. * - * @see #MATCH_CONTENT_FRAME_RATE * @hide */ - public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; + @TestApi + @Readable + @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. + public static final String GLANCEABLE_HUB_ENABLED = "glanceable_hub_enabled"; /** - * Allow refresh rate switching between all refresh rates even if the switch will have - * visual interruptions for the user. + * Indicates that glanceable hub should never be started automatically. * - * @see #MATCH_CONTENT_FRAME_RATE * @hide */ - public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; + public static final int GLANCEABLE_HUB_START_NEVER = 0; /** - * User's preference for refresh rate switching. - * - *

Values: - * 0 - Never switch refresh rates. - * 1 - Switch refresh rates only when it can be done seamlessly. (Default behaviour) - * 2 - Always prefer refresh rate switching even if it's going to have visual interruptions - * for the user. + * Indicates that glanceable hub should be started when charging. * - * @see android.view.Surface#setFrameRate - * @see #MATCH_CONTENT_FRAMERATE_NEVER - * @see #MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY - * @see #MATCH_CONTENT_FRAMERATE_ALWAYS * @hide */ - public static final String MATCH_CONTENT_FRAME_RATE = - "match_content_frame_rate"; + public static final int GLANCEABLE_HUB_START_CHARGING = 1; /** - * INCALL_POWER_BUTTON_BEHAVIOR value for "turn off screen". + * Indicates that glanceable hub should be started when charging and upright. + * * @hide */ - public static final int INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF = 0x1; + public static final int GLANCEABLE_HUB_START_CHARGING_UPRIGHT = 2; /** - * INCALL_POWER_BUTTON_BEHAVIOR value for "hang up". + * Indicates that glanceable hub should be started when docked. + * * @hide */ - public static final int INCALL_POWER_BUTTON_BEHAVIOR_HANGUP = 0x2; + public static final int GLANCEABLE_HUB_START_DOCKED = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + GLANCEABLE_HUB_START_NEVER, + GLANCEABLE_HUB_START_CHARGING, + GLANCEABLE_HUB_START_CHARGING_UPRIGHT, + GLANCEABLE_HUB_START_DOCKED, + }) + public @interface WhenToStartGlanceableHub { + } /** - * INCALL_POWER_BUTTON_BEHAVIOR default value. + * Indicates when to start glanceable hub. Possible values are: + * 0: Never + * 1: While charging always + * 2: While upright and charging + * 3: While docked + * * @hide */ - public static final int INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT = - INCALL_POWER_BUTTON_BEHAVIOR_SCREEN_OFF; + public static final String WHEN_TO_START_GLANCEABLE_HUB = + "when_to_start_glanceable_hub"; /** - * What happens when the user presses the Back button while in-call - * and the screen is on.
- * Values:
- * 0 - The Back buttons does nothing different.
- * 1 - The Back button hangs up the current call.
+ * Whether glanceable hub should only start when charging wirelessly. * * @hide */ - @Readable - public static final String INCALL_BACK_BUTTON_BEHAVIOR = "incall_back_button_behavior"; + public static final String GLANCEABLE_HUB_RESTRICT_TO_WIRELESS_CHARGING = + "glanceable_hub_restrict_to_writeless_charging"; /** - * INCALL_BACK_BUTTON_BEHAVIOR value for no action. + * Nothing should be done during low light + * * @hide */ - public static final int INCALL_BACK_BUTTON_BEHAVIOR_NONE = 0x0; + public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_NONE = 0; /** - * INCALL_BACK_BUTTON_BEHAVIOR value for "hang up". + * The screen should turn completely off in low light. + * * @hide */ - public static final int INCALL_BACK_BUTTON_BEHAVIOR_HANGUP = 0x1; + public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_SCREEN_OFF = 1; /** - * INCALL_POWER_BUTTON_BEHAVIOR default value. + * The screen should switch to a low light clock dream if dreaming is enabled in low light. + * * @hide */ - public static final int INCALL_BACK_BUTTON_BEHAVIOR_DEFAULT = - INCALL_BACK_BUTTON_BEHAVIOR_NONE; + public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_LOW_LIGHT_CLOCK_DREAM = 2; /** - * Whether the device should wake when the wake gesture sensor detects motion. + * The screen should not show dreams if enabled (AOD will be permitted). + * * @hide */ - @Readable - public static final String WAKE_GESTURE_ENABLED = "wake_gesture_enabled"; + public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_NO_DREAM = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + LOW_LIGHT_DISPLAY_BEHAVIOR_NONE, + LOW_LIGHT_DISPLAY_BEHAVIOR_SCREEN_OFF, + LOW_LIGHT_DISPLAY_BEHAVIOR_LOW_LIGHT_CLOCK_DREAM, + LOW_LIGHT_DISPLAY_BEHAVIOR_NO_DREAM, + }) + public @interface LowLightDisplayBehavior { + } /** - * Whether the device should doze if configured. + * Indicates display behavior in low light. Options are: + * 0: None + * 1: Keep screen off + * 2: Show low light clock dream + * 3: Disable dreaming + * * @hide */ - @UnsupportedAppUsage - @Readable - public static final String DOZE_ENABLED = "doze_enabled"; + public static final String LOW_LIGHT_DISPLAY_BEHAVIOR = + "low_light_display_behavior"; /** - * Indicates whether doze should be always on. - *

- * Type: int (0 for false, 1 for true) + * Indicates whether display behavior in low light is enabled. * * @hide */ - @SystemApi - @Readable - public static final String DOZE_ALWAYS_ON = "doze_always_on"; + public static final String LOW_LIGHT_DISPLAY_BEHAVIOR_ENABLED = + "low_light_display_behavior_enabled"; /** - * Indicates whether ambient wallpaper is visible with AOD. - *

- * Type: int (0 for false, 1 for true) + * Whether home controls are enabled to be shown over the screensaver by the user. * * @hide */ - public static final String DOZE_ALWAYS_ON_WALLPAPER_ENABLED = - "doze_always_on_wallpaper_enabled"; + public static final String SCREENSAVER_HOME_CONTROLS_ENABLED = + "screensaver_home_controls_enabled"; /** - * Whether the device should pulse on pick up gesture. + * Whether screensaver should only start when charging wirelessly. + * * @hide */ - @Readable - public static final String DOZE_PICK_UP_GESTURE = "doze_pulse_on_pick_up"; + public static final String SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING = + "screensaver_restrict_to_writeless_charging"; /** - * Whether the device should pulse on long press gesture. + * Default, indicates that the user has not yet started the dock setup flow. + * * @hide */ - @Readable - public static final String DOZE_PULSE_ON_LONG_PRESS = "doze_pulse_on_long_press"; + public static final int DOCK_SETUP_NOT_STARTED = 0; /** - * Whether the device should pulse on double tap gesture. + * Indicates that the user has started but not yet completed dock setup. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - @Readable - public static final String DOZE_DOUBLE_TAP_GESTURE = "doze_pulse_on_double_tap"; + public static final int DOCK_SETUP_STARTED = 1; /** - * Whether the device should respond to the SLPI tap gesture. + * Indicates that the user has snoozed dock setup and will complete it later. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - @Readable - public static final String DOZE_TAP_SCREEN_GESTURE = "doze_tap_gesture"; + public static final int DOCK_SETUP_PAUSED = 2; /** - * Gesture that wakes up the display, showing some version of the lock screen. + * Indicates that the user has been prompted to start dock setup. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - @Readable - public static final String DOZE_WAKE_LOCK_SCREEN_GESTURE = "doze_wake_screen_gesture"; + public static final int DOCK_SETUP_PROMPTED = 3; /** - * Gesture that wakes up the display, toggling between {@link Display.STATE_OFF} and - * {@link Display.STATE_DOZE}. + * Indicates that the user has started dock setup but never finished it. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - @Readable - public static final String DOZE_WAKE_DISPLAY_GESTURE = "doze_wake_display_gesture"; + public static final int DOCK_SETUP_INCOMPLETE = 4; /** - * Gesture that wakes up the display on quick pickup, toggling between - * {@link Display.STATE_OFF} and {@link Display.STATE_DOZE}. + * Indicates that the user has completed dock setup. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - public static final String DOZE_QUICK_PICKUP_GESTURE = "doze_quick_pickup_gesture"; + public static final int DOCK_SETUP_COMPLETED = 10; /** - * Whether the device should suppress the current doze configuration and disable dozing. + * Indicates that dock setup timed out before the user could complete it. + * One of the possible states for {@link #DOCK_SETUP_STATE}. + * * @hide */ - @Readable - public static final String SUPPRESS_DOZE = "suppress_doze"; + public static final int DOCK_SETUP_TIMED_OUT = 11; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + DOCK_SETUP_NOT_STARTED, + DOCK_SETUP_STARTED, + DOCK_SETUP_PAUSED, + DOCK_SETUP_PROMPTED, + DOCK_SETUP_INCOMPLETE, + DOCK_SETUP_COMPLETED, + DOCK_SETUP_TIMED_OUT + }) + public @interface DockSetupState { + } /** - * Gesture that skips media. + * Defines the user's current state of dock setup. + * The possible states are defined in {@link DockSetupState}. + * * @hide */ - @Readable - public static final String SKIP_GESTURE = "skip_gesture"; + public static final String DOCK_SETUP_STATE = "dock_setup_state"; + /** - * Count of successful gestures. + * Default, indicates that the user has not yet started the hub mode tutorial. + * * @hide */ - @Readable - public static final String SKIP_GESTURE_COUNT = "skip_gesture_count"; + public static final int HUB_MODE_TUTORIAL_NOT_STARTED = 0; /** - * Count of non-gesture interaction. + * Indicates that the user has started but not yet completed the hub mode tutorial. + * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * * @hide */ - @Readable - public static final String SKIP_TOUCH_COUNT = "skip_touch_count"; + public static final int HUB_MODE_TUTORIAL_STARTED = 1; /** - * Direction to advance media for skip gesture + * Any value greater than or equal to this value is considered that the user has + * completed the hub mode tutorial. + * + * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * * @hide */ - @Readable - public static final String SKIP_DIRECTION = "skip_gesture_direction"; + public static final int HUB_MODE_TUTORIAL_COMPLETED = 10; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + HUB_MODE_TUTORIAL_NOT_STARTED, + HUB_MODE_TUTORIAL_STARTED, + HUB_MODE_TUTORIAL_COMPLETED + }) + public @interface HubModeTutorialState { + } /** - * Gesture that silences sound (alarms, notification, calls). + * Defines the user's current state of navigating through the hub mode tutorial. + * Some possible states are defined in {@link HubModeTutorialState}. + * + * Any value greater than or equal to {@link HUB_MODE_TUTORIAL_COMPLETED} indicates that + * the user has completed that version of the hub mode tutorial. And tutorial may be + * shown again when a new version becomes available. * @hide */ - @Readable - public static final String SILENCE_GESTURE = "silence_gesture"; + public static final String HUB_MODE_TUTORIAL_STATE = "hub_mode_tutorial_state"; /** - * Count of successful silence alarms gestures. + * The default NFC payment component + * + * @deprecated please use {@link android.app.role.RoleManager#getRoleHolders(String)} + * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter. * @hide */ - @Readable - public static final String SILENCE_ALARMS_GESTURE_COUNT = "silence_alarms_gesture_count"; + @Deprecated + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; /** - * Count of successful silence timer gestures. + * Whether NFC payment is handled by the foreground application or a default. * @hide */ @Readable - public static final String SILENCE_TIMER_GESTURE_COUNT = "silence_timer_gesture_count"; + public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground"; /** - * Count of successful silence call gestures. + * Specifies the package name currently configured to be the primary sms application * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String SILENCE_CALL_GESTURE_COUNT = "silence_call_gesture_count"; + public static final String SMS_DEFAULT_APPLICATION = "sms_default_application"; /** - * Count of non-gesture interaction. + * Specifies the package name currently configured to be the default dialer application * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String SILENCE_ALARMS_TOUCH_COUNT = "silence_alarms_touch_count"; + public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application"; /** - * Count of non-gesture interaction. + * Specifies the component name currently configured to be the default call screening + * application * @hide */ @Readable - public static final String SILENCE_TIMER_TOUCH_COUNT = "silence_timer_touch_count"; + public static final String CALL_SCREENING_DEFAULT_COMPONENT = + "call_screening_default_component"; /** - * Count of non-gesture interaction. + * Specifies the package name currently configured to be the emergency assistance application + * + * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE + * * @hide */ @Readable - public static final String SILENCE_CALL_TOUCH_COUNT = "silence_call_touch_count"; + public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application"; /** - * Number of successful "Motion Sense" tap gestures to pause media. + * Specifies whether the current app context on scren (assist data) will be sent to the + * assist application (active voice interaction service). + * * @hide */ @Readable - public static final String AWARE_TAP_PAUSE_GESTURE_COUNT = "aware_tap_pause_gesture_count"; + public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled"; /** - * Number of touch interactions to pause media when a "Motion Sense" gesture could - * have been used. + * Specifies whether a screenshot of the screen contents will be sent to the assist + * application (active voice interaction service). + * * @hide */ @Readable - public static final String AWARE_TAP_PAUSE_TOUCH_COUNT = "aware_tap_pause_touch_count"; + public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled"; /** - * For user preference if swipe bottom to expand notification gesture enabled. + * Specifies whether the screen will show an animation if screen contents are sent to the + * assist application (active voice interaction service). + * + * Note that the disclosure will be forced for third-party assistants or if the device + * does not support disabling it. + * * @hide */ - public static final String SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED = - "swipe_bottom_to_notification_enabled"; + @Readable + public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled"; /** - * Controls whether One-Handed mode is currently activated. + * Control if rotation suggestions are sent to System UI when in rotation locked mode. + * Done to enable screen rotation while the screen rotation is locked. Enabling will + * poll the accelerometer in rotation locked mode. + * + * If 0, then rotation suggestions are not sent to System UI. If 1, suggestions are sent. + * * @hide */ - public static final String ONE_HANDED_MODE_ACTIVATED = "one_handed_mode_activated"; + @Readable + public static final String SHOW_ROTATION_SUGGESTIONS = "show_rotation_suggestions"; /** - * For user preference if One-Handed Mode enabled. + * The disabled state of SHOW_ROTATION_SUGGESTIONS. * @hide */ - public static final String ONE_HANDED_MODE_ENABLED = "one_handed_mode_enabled"; + public static final int SHOW_ROTATION_SUGGESTIONS_DISABLED = 0x0; /** - * For user preference if One-Handed Mode timeout. + * The enabled state of SHOW_ROTATION_SUGGESTIONS. * @hide */ - public static final String ONE_HANDED_MODE_TIMEOUT = "one_handed_mode_timeout"; + public static final int SHOW_ROTATION_SUGGESTIONS_ENABLED = 0x1; /** - * For user taps app to exit One-Handed Mode. + * The default state of SHOW_ROTATION_SUGGESTIONS. * @hide */ - public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit"; + public static final int SHOW_ROTATION_SUGGESTIONS_DEFAULT = + SHOW_ROTATION_SUGGESTIONS_ENABLED; /** - * Internal use, one handed mode tutorial showed times. + * The number of accepted rotation suggestions. Used to determine if the user has been + * introduced to rotation suggestions. * @hide */ - public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT = - "one_handed_tutorial_show_count"; + @Readable + public static final String NUM_ROTATION_SUGGESTIONS_ACCEPTED = + "num_rotation_suggestions_accepted"; /** - * Toggle to enable/disable for the apps to use the Ui translation for Views. The value - * indicates whether the Ui translation is enabled by the user. - *

- * Type: {@code int} ({@code 0} for disabled, {@code 1} for enabled) + * Read only list of the service components that the current user has explicitly allowed to + * see and assist with all of the user's notifications. * + * @deprecated Use + * {@link NotificationManager#isNotificationAssistantAccessGranted(ComponentName)}. * @hide */ - @SystemApi + @Deprecated @Readable - @SuppressLint("NoSettingsProvider") - public static final String UI_TRANSLATION_ENABLED = "ui_translation_enabled"; + public static final String ENABLED_NOTIFICATION_ASSISTANT = + "enabled_notification_assistant"; /** - * The current night mode that has been selected by the user. Owned - * and controlled by UiModeManagerService. Constants are as per - * UiModeManager. + * Read only list of the service components that the current user has explicitly allowed to + * see all of the user's notifications, separated by ':'. + * * @hide + * @deprecated Use + * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)}. */ + @Deprecated + @UnsupportedAppUsage @Readable - public static final String UI_NIGHT_MODE = "ui_night_mode"; + public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; /** - * The current night mode custom type that has been selected by the user. Owned - * and controlled by UiModeManagerService. Constants are as per UiModeManager. + * Read only list of the packages that the current user has explicitly allowed to + * manage do not disturb, separated by ':'. + * + * @deprecated Use {@link NotificationManager#isNotificationPolicyAccessGranted()}. * @hide */ + @Deprecated + @TestApi @Readable - @SuppressLint("NoSettingsProvider") - public static final String UI_NIGHT_MODE_CUSTOM_TYPE = "ui_night_mode_custom_type"; + public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = + "enabled_notification_policy_access_packages"; /** - * The current night mode that has been overridden to turn on by the system. Owned - * and controlled by UiModeManagerService. Constants are as per - * UiModeManager. + * Defines whether managed profile ringtones should be synced from it's parent profile + *

+ * 0 = ringtones are not synced + * 1 = ringtones are synced from the profile's parent (default) + *

+ * This value is only used for managed profiles. * @hide */ + @TestApi @Readable - public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on"; + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; /** - * The last computed night mode bool the last time the phone was on * @hide */ - public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi + @Readable + public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations"; /** - * The current night mode that has been overridden to turn off by the system. Owned - * and controlled by UiModeManagerService. Constants are as per - * UiModeManager. + * This is the query URI for finding a print service to install. + * * @hide */ @Readable - public static final String UI_NIGHT_MODE_OVERRIDE_OFF = "ui_night_mode_override_off"; + public static final String PRINT_SERVICE_SEARCH_URI = "print_service_search_uri"; /** - * Whether screensavers are enabled. + * This is the query URI for finding a NFC payment service to install. + * * @hide */ @Readable - public static final String SCREENSAVER_ENABLED = "screensaver_enabled"; + public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri"; /** - * The user's chosen screensaver components. + * This is the query URI for finding a auto fill service to install. * - * These will be launched by the PhoneWindowManager after a timeout when not on - * battery, or upon dock insertion (if SCREENSAVER_ACTIVATE_ON_DOCK is set to 1). * @hide */ @Readable - public static final String SCREENSAVER_COMPONENTS = "screensaver_components"; + public static final String AUTOFILL_SERVICE_SEARCH_URI = "autofill_service_search_uri"; /** - * If screensavers are enabled, whether the screensaver should be automatically launched - * when the device is inserted into a (desk) dock. - * @hide + * If enabled, apps should try to skip any introductory hints on first launch. This might + * apply to users that are already familiar with the environment or temporary users. + *

+ * Type : int (0 to show hints, 1 to skip showing hints) */ @Readable - public static final String SCREENSAVER_ACTIVATE_ON_DOCK = "screensaver_activate_on_dock"; + public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints"; /** - * If screensavers are enabled, whether the screensaver should be automatically launched - * when the screen times out when not on battery. + * Persisted playback time after a user confirmation of an unsafe volume level. + * * @hide */ @Readable - public static final String SCREENSAVER_ACTIVATE_ON_SLEEP = "screensaver_activate_on_sleep"; + public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; /** - * If screensavers are enabled, whether the screensaver should be - * automatically launched when the device is stationary and upright. + * Indicates whether the spatial audio feature was enabled for this user. + * + * Type : int (0 disabled, 1 enabled) + * * @hide */ - @Readable - public static final String SCREENSAVER_ACTIVATE_ON_POSTURED = - "screensaver_activate_on_postured"; + public static final String SPATIAL_AUDIO_ENABLED = "spatial_audio_enabled"; /** - * If screensavers are enabled, the default screensaver component. + * Internal collection of audio device inventory items + * The device item stored are {@link com.android.server.audio.AdiDeviceState} * @hide */ - @Readable - public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component"; + public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory"; /** - * Whether complications are enabled to be shown over the screensaver by the user. - * + * Stores a boolean that defines whether the CSD as a feature is enabled or not. * @hide */ - public static final String SCREENSAVER_COMPLICATIONS_ENABLED = - "screensaver_complications_enabled"; + public static final String AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED = + "audio_safe_csd_as_a_feature_enabled"; /** - * Defines the enabled state for the glanceable hub. + * Indicates whether notification display on the lock screen is enabled. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - @TestApi + @SystemApi @Readable - @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support. - public static final String GLANCEABLE_HUB_ENABLED = "glanceable_hub_enabled"; + public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = + "lock_screen_show_notifications"; /** - * Indicates that glanceable hub should never be started automatically. + * Indicates whether the lock screen should display silent notifications. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - public static final int GLANCEABLE_HUB_START_NEVER = 0; + @Readable + public static final String LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS = + "lock_screen_show_silent_notifications"; /** - * Indicates that glanceable hub should be started when charging. + * Indicates whether "seen" notifications should be suppressed from the lockscreen. + *

+ * Type: int (0 for unset_off, 1 for true, 2 for false) + * 0 is the default value for phones, which is equivalent to off in effect, before + * the notification minimalism feature, this setting is default hidden to phones, we use + * 0 instead of 2 to mark that we need to hide this setting toggle in the Settings app. * * @hide */ - public static final int GLANCEABLE_HUB_START_CHARGING = 1; + public static final String LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS = + "lock_screen_show_only_unseen_notifications"; /** - * Indicates that glanceable hub should be started when charging and upright. + * Indicates whether to minimalize the number of notifications to show on the lockscreen. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - public static final int GLANCEABLE_HUB_START_CHARGING_UPRIGHT = 2; + public static final String LOCK_SCREEN_NOTIFICATION_MINIMALISM = + "lock_screen_notification_minimalism"; /** - * Indicates that glanceable hub should be started when docked. + * Indicates whether snooze options should be shown on notifications + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - public static final int GLANCEABLE_HUB_START_DOCKED = 3; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - GLANCEABLE_HUB_START_NEVER, - GLANCEABLE_HUB_START_CHARGING, - GLANCEABLE_HUB_START_CHARGING_UPRIGHT, - GLANCEABLE_HUB_START_DOCKED, - }) - public @interface WhenToStartGlanceableHub { - } + @Readable + public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze"; /** - * Indicates when to start glanceable hub. Possible values are: - * 0: Never - * 1: While charging always - * 2: While upright and charging - * 3: While docked + * Controls whether dual shade is enabled. This splits notifications and quick settings to + * have their own independently expandable/collapsible panels, appearing on either side of + * the large screen (including unfolded device) or sharing a space on a narrow screen + * (including a folded device). Both panels will now cover the screen only partially + * (wrapping their content), so a running app or the lockscreen will remain visible in the + * background. + *

+ * Type: int (0 for false, 1 for true) * * @hide */ - public static final String WHEN_TO_START_GLANCEABLE_HUB = - "when_to_start_glanceable_hub"; + @android.provider.Settings.Readable + public static final String DUAL_SHADE = "dual_shade"; - /** - * Whether glanceable hub should only start when charging wirelessly. - * + /** + * 1 if it is allowed to remove the primary GAIA account. 0 by default. * @hide */ - public static final String GLANCEABLE_HUB_RESTRICT_TO_WIRELESS_CHARGING = - "glanceable_hub_restrict_to_writeless_charging"; + public static final String ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS = + "allow_primary_gaia_account_removal_for_tests"; /** - * Nothing should be done during low light - * + * List of TV inputs that are currently hidden. This is a string + * containing the IDs of all hidden TV inputs. Each ID is encoded by + * {@link android.net.Uri#encode(String)} and separated by ':'. * @hide */ - public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_NONE = 0; + @Readable + public static final String TV_INPUT_HIDDEN_INPUTS = "tv_input_hidden_inputs"; /** - * The screen should turn completely off in low light. - * + * List of custom TV input labels. This is a string containing + * pairs. TV input id and custom name are encoded by {@link android.net.Uri#encode(String)} + * and separated by ','. Each pair is separated by ':'. * @hide */ - public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_SCREEN_OFF = 1; + @Readable + public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels"; /** - * The screen should switch to a low light clock dream if dreaming is enabled in low light. + * Whether TV app uses non-system inputs. + * + *

+ * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed, + * and 0 means non-system TV inputs are not allowed. + * + *

+ * Devices such as sound bars may have changed the system property allow_third_party_inputs + * to false so the TV Application only uses HDMI and other built in inputs. This setting + * allows user to override the default and have the TV Application use third party TV inputs + * available on play store. * * @hide */ - public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_LOW_LIGHT_CLOCK_DREAM = 2; + @Readable + public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs"; /** - * The screen should not show dreams if enabled (AOD will be permitted). + * Whether automatic routing of system audio to USB audio peripheral is disabled. + * The value is boolean (1 or 0), where 1 means automatic routing is disabled, + * and 0 means automatic routing is enabled. * * @hide */ - public static final int LOW_LIGHT_DISPLAY_BEHAVIOR_NO_DREAM = 3; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - LOW_LIGHT_DISPLAY_BEHAVIOR_NONE, - LOW_LIGHT_DISPLAY_BEHAVIOR_SCREEN_OFF, - LOW_LIGHT_DISPLAY_BEHAVIOR_LOW_LIGHT_CLOCK_DREAM, - LOW_LIGHT_DISPLAY_BEHAVIOR_NO_DREAM, - }) - public @interface LowLightDisplayBehavior { - } + @Readable + public static final String USB_AUDIO_AUTOMATIC_ROUTING_DISABLED = + "usb_audio_automatic_routing_disabled"; /** - * Indicates display behavior in low light. Options are: - * 0: None - * 1: Keep screen off - * 2: Show low light clock dream - * 3: Disable dreaming + * The timeout in milliseconds before the device fully goes to sleep after + * a period of inactivity. This value sets an upper bound on how long the device + * will stay awake or dreaming without user activity. It should generally + * be longer than {@link Settings.System#SCREEN_OFF_TIMEOUT} as otherwise the device + * will sleep before it ever has a chance to dream. + *

+ * Use -1 to disable this timeout. + *

* * @hide */ - public static final String LOW_LIGHT_DISPLAY_BEHAVIOR = - "low_light_display_behavior"; + @Readable + public static final String SLEEP_TIMEOUT = "sleep_timeout"; /** - * Indicates whether display behavior in low light is enabled. + * The timeout in milliseconds before the device goes to sleep due to user inattentiveness, + * even if the system is holding wakelocks. It should generally be longer than {@code + * config_attentiveWarningDuration}, as otherwise the device will show the attentive + * warning constantly. Small timeouts are discouraged, as they will cause the device to + * go to sleep quickly after waking up. + *

+ * Use -1 to disable this timeout. + *

* * @hide */ - public static final String LOW_LIGHT_DISPLAY_BEHAVIOR_ENABLED = - "low_light_display_behavior_enabled"; + @Readable + public static final String ATTENTIVE_TIMEOUT = "attentive_timeout"; /** - * Whether home controls are enabled to be shown over the screensaver by the user. - * + * Controls whether double tap to wake is enabled. * @hide */ - public static final String SCREENSAVER_HOME_CONTROLS_ENABLED = - "screensaver_home_controls_enabled"; + @Readable + public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake"; /** - * Whether screensaver should only start when charging wirelessly. - * + * Controls whether double tap to sleep is enabled. * @hide */ - public static final String SCREENSAVER_RESTRICT_TO_WIRELESS_CHARGING = - "screensaver_restrict_to_writeless_charging"; + public static final String DOUBLE_TAP_TO_SLEEP = "double_tap_to_sleep"; /** - * Default, indicates that the user has not yet started the dock setup flow. + * The current assistant component. It could be a voice interaction service, + * or an activity that handles ACTION_ASSIST, or empty which means using the default + * handling. + * + *

This should be set indirectly by setting the {@link + * android.app.role.RoleManager#ROLE_ASSISTANT assistant role}. * * @hide */ - public static final int DOCK_SETUP_NOT_STARTED = 0; + @UnsupportedAppUsage + @Readable + public static final String ASSISTANT = "assistant"; /** - * Indicates that the user has started but not yet completed dock setup. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * Whether the camera launch gesture should be disabled. * * @hide */ - public static final int DOCK_SETUP_STARTED = 1; + @Readable + public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled"; /** - * Indicates that the user has snoozed dock setup and will complete it later. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * Whether the emergency gesture should be enabled. * * @hide */ - public static final int DOCK_SETUP_PAUSED = 2; + public static final String EMERGENCY_GESTURE_ENABLED = "emergency_gesture_enabled"; /** - * Indicates that the user has been prompted to start dock setup. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * Whether the emergency gesture sound should be enabled. * * @hide */ - public static final int DOCK_SETUP_PROMPTED = 3; + public static final String EMERGENCY_GESTURE_SOUND_ENABLED = + "emergency_gesture_sound_enabled"; /** - * Indicates that the user has started dock setup but never finished it. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * Whether the emergency gesture UI is currently showing. * * @hide */ - public static final int DOCK_SETUP_INCOMPLETE = 4; + public static final String EMERGENCY_GESTURE_UI_SHOWING = "emergency_gesture_ui_showing"; /** - * Indicates that the user has completed dock setup. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * The last time the emergency gesture UI was started. * * @hide */ - public static final int DOCK_SETUP_COMPLETED = 10; + public static final String EMERGENCY_GESTURE_UI_LAST_STARTED_MILLIS = + "emergency_gesture_ui_last_started_millis"; /** - * Indicates that dock setup timed out before the user could complete it. - * One of the possible states for {@link #DOCK_SETUP_STATE}. + * Whether double tap the power button gesture is enabled. * * @hide */ - public static final int DOCK_SETUP_TIMED_OUT = 11; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - DOCK_SETUP_NOT_STARTED, - DOCK_SETUP_STARTED, - DOCK_SETUP_PAUSED, - DOCK_SETUP_PROMPTED, - DOCK_SETUP_INCOMPLETE, - DOCK_SETUP_COMPLETED, - DOCK_SETUP_TIMED_OUT - }) - public @interface DockSetupState { - } + @Readable + public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED = + "double_tap_power_button_gesture_enabled"; /** - * Defines the user's current state of dock setup. - * The possible states are defined in {@link DockSetupState}. - * + * Double tap power button gesture behavior. + * 0 = Camera launch + * 1 = Wallet launch * @hide */ - public static final String DOCK_SETUP_STATE = "dock_setup_state"; - + @Readable + public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE = + "double_tap_power_button_gesture"; /** - * Default, indicates that the user has not yet started the hub mode tutorial. + * Whether the camera launch gesture to double tap the power button when the screen is off + * should be disabled. * * @hide */ - public static final int HUB_MODE_TUTORIAL_NOT_STARTED = 0; + @Readable + public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED = + "camera_double_tap_power_gesture_disabled"; /** - * Indicates that the user has started but not yet completed the hub mode tutorial. - * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * Whether the camera double twist gesture to flip between front and back mode should be + * enabled. * * @hide */ - public static final int HUB_MODE_TUTORIAL_STARTED = 1; + @Readable + public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED = + "camera_double_twist_to_flip_enabled"; /** - * Any value greater than or equal to this value is considered that the user has - * completed the hub mode tutorial. - * - * One of the possible states for {@link #HUB_MODE_TUTORIAL_STATE}. + * Whether or not the smart camera lift trigger that launches the camera when the user moves + * the phone into a position for taking photos should be enabled. * * @hide */ - public static final int HUB_MODE_TUTORIAL_COMPLETED = 10; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - HUB_MODE_TUTORIAL_NOT_STARTED, - HUB_MODE_TUTORIAL_STARTED, - HUB_MODE_TUTORIAL_COMPLETED - }) - public @interface HubModeTutorialState { - } + @Readable + public static final String CAMERA_LIFT_TRIGGER_ENABLED = "camera_lift_trigger_enabled"; /** - * Defines the user's current state of navigating through the hub mode tutorial. - * Some possible states are defined in {@link HubModeTutorialState}. + * The default enable state of the camera lift trigger. * - * Any value greater than or equal to {@link HUB_MODE_TUTORIAL_COMPLETED} indicates that - * the user has completed that version of the hub mode tutorial. And tutorial may be - * shown again when a new version becomes available. * @hide */ - public static final String HUB_MODE_TUTORIAL_STATE = "hub_mode_tutorial_state"; + public static final int CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT = 1; /** - * The default NFC payment component + * Whether or not the flashlight (camera torch mode) is available required to turn + * on flashlight. * - * @deprecated please use {@link android.app.role.RoleManager#getRoleHolders(String)} - * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter. * @hide */ - @Deprecated - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; + @Readable + public static final String FLASHLIGHT_AVAILABLE = "flashlight_available"; /** - * Whether NFC payment is handled by the foreground application or a default. + * Whether or not flashlight is enabled. + * * @hide */ @Readable - public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground"; + public static final String FLASHLIGHT_ENABLED = "flashlight_enabled"; /** - * Specifies the package name currently configured to be the primary sms application + * Whether or not face unlock is allowed on Keyguard. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String SMS_DEFAULT_APPLICATION = "sms_default_application"; + public static final String FACE_UNLOCK_KEYGUARD_ENABLED = "face_unlock_keyguard_enabled"; /** - * Specifies the package name currently configured to be the default dialer application + * Whether or not face unlock dismisses the keyguard. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @Readable - public static final String DIALER_DEFAULT_APPLICATION = "dialer_default_application"; + public static final String FACE_UNLOCK_DISMISSES_KEYGUARD = + "face_unlock_dismisses_keyguard"; /** - * Specifies the component name currently configured to be the default call screening - * application + * Whether or not media is shown automatically when bypassing as a heads up. * @hide */ @Readable - public static final String CALL_SCREENING_DEFAULT_COMPONENT = - "call_screening_default_component"; + public static final String SHOW_MEDIA_WHEN_BYPASSING = + "show_media_when_bypassing"; /** - * Specifies the package name currently configured to be the emergency assistance application - * - * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE - * + * Whether or not face unlock requires attention. This is a cached value, the source of + * truth is obtained through the HAL. * @hide */ @Readable - public static final String EMERGENCY_ASSISTANCE_APPLICATION = "emergency_assistance_application"; + public static final String FACE_UNLOCK_ATTENTION_REQUIRED = + "face_unlock_attention_required"; /** - * Specifies whether the current app context on scren (assist data) will be sent to the - * assist application (active voice interaction service). - * + * Whether or not face unlock requires a diverse set of poses during enrollment. This is a + * cached value, the source of truth is obtained through the HAL. * @hide */ @Readable - public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled"; + public static final String FACE_UNLOCK_DIVERSITY_REQUIRED = + "face_unlock_diversity_required"; + /** - * Specifies whether a screenshot of the screen contents will be sent to the assist - * application (active voice interaction service). - * + * Whether or not face unlock is allowed for apps (through BiometricPrompt). * @hide */ @Readable - public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled"; + public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled"; /** - * Specifies whether the screen will show an animation if screen contents are sent to the - * assist application (active voice interaction service). - * - * Note that the disclosure will be forced for third-party assistants or if the device - * does not support disabling it. - * + * Whether or not face unlock always requires user confirmation, meaning {@link + * android.hardware.biometrics.BiometricPrompt.Builder#setConfirmationRequired(boolean)} + * is always 'true'. This overrides the behavior that apps choose in the + * setConfirmationRequired API. * @hide */ @Readable - public static final String ASSIST_DISCLOSURE_ENABLED = "assist_disclosure_enabled"; + public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION = + "face_unlock_always_require_confirmation"; /** - * Control if rotation suggestions are sent to System UI when in rotation locked mode. - * Done to enable screen rotation while the screen rotation is locked. Enabling will - * poll the accelerometer in rotation locked mode. + * Whether or not a user should re enroll their face. * - * If 0, then rotation suggestions are not sent to System UI. If 1, suggestions are sent. + * Face unlock re enroll. + * 0 = No re enrollment. + * 1 = Re enrollment is required. * * @hide */ @Readable - public static final String SHOW_ROTATION_SUGGESTIONS = "show_rotation_suggestions"; + public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll"; /** - * The disabled state of SHOW_ROTATION_SUGGESTIONS. + * The time (in millis) to wait for a power button before sending a + * successful auth in to keyguard(for side fingerprint) * @hide */ - public static final int SHOW_ROTATION_SUGGESTIONS_DISABLED = 0x0; + @Readable + public static final String FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW = + "fingerprint_side_fps_kg_power_window"; /** - * The enabled state of SHOW_ROTATION_SUGGESTIONS. + * The time (in millis) to wait for a power button before sending + * a successful auth in biometric prompt(for side fingerprint) * @hide */ - public static final int SHOW_ROTATION_SUGGESTIONS_ENABLED = 0x1; + @Readable + public static final String FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW = + "fingerprint_side_fps_bp_power_window"; /** - * The default state of SHOW_ROTATION_SUGGESTIONS. + * The time (in millis) that a finger tap will wait for a power button + * before dismissing the power dialog during enrollment(for side + * fingerprint) * @hide */ - public static final int SHOW_ROTATION_SUGGESTIONS_DEFAULT = - SHOW_ROTATION_SUGGESTIONS_ENABLED; + @Readable + public static final String FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW = + "fingerprint_side_fps_enroll_tap_window"; /** - * The number of accepted rotation suggestions. Used to determine if the user has been - * introduced to rotation suggestions. + * The time (in millis) that a power event will ignore future authentications + * (for side fingerprint) * @hide */ @Readable - public static final String NUM_ROTATION_SUGGESTIONS_ACCEPTED = - "num_rotation_suggestions_accepted"; + public static final String FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME = + "fingerprint_side_fps_auth_downtime"; /** - * Read only list of the service components that the current user has explicitly allowed to - * see and assist with all of the user's notifications. - * - * @deprecated Use - * {@link NotificationManager#isNotificationAssistantAccessGranted(ComponentName)}. + * Whether or not a SFPS device is enabling the performant auth setting. + * The "_V2" suffix was added to re-introduce the default behavior for + * users. See b/265264294 fore more details. * @hide */ - @Deprecated - @Readable - public static final String ENABLED_NOTIFICATION_ASSISTANT = - "enabled_notification_assistant"; + public static final String SFPS_PERFORMANT_AUTH_ENABLED = "sfps_performant_auth_enabled_v2"; /** - * Read only list of the service components that the current user has explicitly allowed to - * see all of the user's notifications, separated by ':'. - * + * Whether or not the UDFPS device is enabling the screen off unlock settings. * @hide - * @deprecated Use - * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)}. */ - @Deprecated - @UnsupportedAppUsage + @TestApi @Readable - public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; + @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi without associated feature + public static final String SCREEN_OFF_UNLOCK_UDFPS_ENABLED = "screen_off_udfps_enabled"; /** - * Read only list of the packages that the current user has explicitly allowed to - * manage do not disturb, separated by ':'. - * - * @deprecated Use {@link NotificationManager#isNotificationPolicyAccessGranted()}. + * Whether or not debugging is enabled. * @hide */ - @Deprecated - @TestApi @Readable - public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = - "enabled_notification_policy_access_packages"; + public static final String BIOMETRIC_DEBUG_ENABLED = + "biometric_debug_enabled"; /** - * Defines whether managed profile ringtones should be synced from it's parent profile - *

- * 0 = ringtones are not synced - * 1 = ringtones are synced from the profile's parent (default) - *

- * This value is only used for managed profiles. + * Whether or not both fingerprint and face virtual sensors are enabled. * @hide */ @TestApi @Readable - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds"; + public static final String BIOMETRIC_VIRTUAL_ENABLED = "biometric_virtual_enabled"; /** + * Whether or not fingerprint virtual sensors are enabled. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi - @Readable - public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations"; + @FlaggedApi("com.android.server.biometrics.face_vhal_feature") + public static final String BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED = + "biometric_fingerprint_virtual_enabled"; /** - * This is the query URI for finding a print service to install. - * + * Whether or not face virtual sensors are enabled. * @hide */ - @Readable - public static final String PRINT_SERVICE_SEARCH_URI = "print_service_search_uri"; + @FlaggedApi("com.android.server.biometrics.face_vhal_feature") + public static final String BIOMETRIC_FACE_VIRTUAL_ENABLED = + "biometric_face_virtual_enabled"; /** - * This is the query URI for finding a NFC payment service to install. + * Whether or not biometric is allowed on Keyguard. + * + * @deprecated Use {@link #FINGERPRINT_KEYGUARD_ENABLED} or {@link #FACE_KEYGUARD_ENABLED} + * instead. * * @hide */ + @Deprecated @Readable - public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri"; + public static final String BIOMETRIC_KEYGUARD_ENABLED = "biometric_keyguard_enabled"; /** - * This is the query URI for finding a auto fill service to install. + * Whether or not biometric is allowed for apps (through BiometricPrompt). + * + * @deprecated Use {@link #FINGERPRINT_APP_ENABLED} or {@link #FACE_APP_ENABLED} instead. * * @hide */ + @Deprecated @Readable - public static final String AUTOFILL_SERVICE_SEARCH_URI = "autofill_service_search_uri"; + public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled"; /** - * If enabled, apps should try to skip any introductory hints on first launch. This might - * apply to users that are already familiar with the environment or temporary users. - *

- * Type : int (0 to show hints, 1 to skip showing hints) + * Whether or not fingerprint is allowed on Keyguard. + * @hide */ @Readable - public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints"; + public static final String FINGERPRINT_KEYGUARD_ENABLED = "fingerprint_keyguard_enabled"; /** - * Persisted playback time after a user confirmation of an unsafe volume level. - * + * Whether or not fingerprint is allowed for apps (through BiometricPrompt). * @hide */ @Readable - public static final String UNSAFE_VOLUME_MUSIC_ACTIVE_MS = "unsafe_volume_music_active_ms"; + public static final String FINGERPRINT_APP_ENABLED = "fingerptint_app_enabled"; /** - * Indicates whether the spatial audio feature was enabled for this user. - * - * Type : int (0 disabled, 1 enabled) - * + * Whether or not face is allowed on Keyguard. * @hide */ - public static final String SPATIAL_AUDIO_ENABLED = "spatial_audio_enabled"; + @Readable + public static final String FACE_KEYGUARD_ENABLED = "face_keyguard_enabled"; /** - * Internal collection of audio device inventory items - * The device item stored are {@link com.android.server.audio.AdiDeviceState} + * Whether or not face is allowed for apps (through BiometricPrompt). * @hide */ - public static final String AUDIO_DEVICE_INVENTORY = "audio_device_inventory"; + @Readable + public static final String FACE_APP_ENABLED = "face_app_enabled"; /** - * Stores a boolean that defines whether the CSD as a feature is enabled or not. + * Whether or not mandatory biometrics is enabled. * @hide */ - public static final String AUDIO_SAFE_CSD_AS_A_FEATURE_ENABLED = - "audio_safe_csd_as_a_feature_enabled"; + public static final String MANDATORY_BIOMETRICS = "mandatory_biometrics"; /** - * Indicates whether notification display on the lock screen is enabled. - *

- * Type: int (0 for false, 1 for true) - * + * Whether or not requirements for mandatory biometrics is satisfied. * @hide */ - @SystemApi - @Readable - public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = - "lock_screen_show_notifications"; + public static final String MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED = + "mandatory_biometrics_requirements_satisfied"; /** - * Indicates whether the lock screen should display silent notifications. - *

- * Type: int (0 for false, 1 for true) - * + * Whether or not active unlock triggers on wake. * @hide */ - @Readable - public static final String LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS = - "lock_screen_show_silent_notifications"; + public static final String ACTIVE_UNLOCK_ON_WAKE = "active_unlock_on_wake"; /** - * Indicates whether "seen" notifications should be suppressed from the lockscreen. - *

- * Type: int (0 for unset_off, 1 for true, 2 for false) - * 0 is the default value for phones, which is equivalent to off in effect, before - * the notification minimalism feature, this setting is default hidden to phones, we use - * 0 instead of 2 to mark that we need to hide this setting toggle in the Settings app. - * + * Whether or not active unlock triggers on unlock intent. * @hide */ - public static final String LOCK_SCREEN_SHOW_ONLY_UNSEEN_NOTIFICATIONS = - "lock_screen_show_only_unseen_notifications"; + public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT = + "active_unlock_on_unlock_intent"; /** - * Indicates whether to minimalize the number of notifications to show on the lockscreen. - *

- * Type: int (0 for false, 1 for true) - * + * Whether or not active unlock triggers on biometric failure. * @hide */ - public static final String LOCK_SCREEN_NOTIFICATION_MINIMALISM = - "lock_screen_notification_minimalism"; + public static final String ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL = + "active_unlock_on_biometric_fail"; /** - * Indicates whether snooze options should be shown on notifications - *

- * Type: int (0 for false, 1 for true) - * + * Whether or not active unlock triggers on legacy unlock intents. * @hide */ - @Readable - public static final String SHOW_NOTIFICATION_SNOOZE = "show_notification_snooze"; + public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_LEGACY = + "active_unlock_on_unlock_intent_legacy"; /** - * Controls whether dual shade is enabled. This splits notifications and quick settings to - * have their own independently expandable/collapsible panels, appearing on either side of - * the large screen (including unfolded device) or sharing a space on a narrow screen - * (including a folded device). Both panels will now cover the screen only partially - * (wrapping their content), so a running app or the lockscreen will remain visible in the - * background. - *

- * Type: int (0 for false, 1 for true) - * + * If active unlock triggers on biometric failures, include the following error codes + * as a biometric failure. See {@link android.hardware.biometrics.BiometricFaceConstants}. + * Error codes should be separated by a pipe. For example: "1|4|5". If active unlock + * should never trigger on any face errors, this should be set to an empty string. + * A null value will use the system default value (TIMEOUT). * @hide */ - @android.provider.Settings.Readable - public static final String DUAL_SHADE = "dual_shade"; + public static final String ACTIVE_UNLOCK_ON_FACE_ERRORS = + "active_unlock_on_face_errors"; - /** - * 1 if it is allowed to remove the primary GAIA account. 0 by default. + /** + * If active unlock triggers on biometric failures, include the following acquired info + * as a "biometric failure". See {@link android.hardware.biometrics.BiometricFaceConstants}. + * Acquired codes should be separated by a pipe. For example: "1|4|5". If active unlock + * should never on trigger on any acquired info messages, this should be + * set to an empty string. A null value will use the system default value (none). * @hide */ - public static final String ALLOW_PRIMARY_GAIA_ACCOUNT_REMOVAL_FOR_TESTS = - "allow_primary_gaia_account_removal_for_tests"; + public static final String ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO = + "active_unlock_on_face_acquire_info"; /** - * List of TV inputs that are currently hidden. This is a string - * containing the IDs of all hidden TV inputs. Each ID is encoded by - * {@link android.net.Uri#encode(String)} and separated by ':'. + * If active unlock triggers on biometric failures, then also request active unlock on + * unlock intent when each setting (BiometricType) is the only biometric type enrolled. + * Biometric types should be separated by a pipe. For example: "0|3" or "0". If this + * setting should be disabled, then this should be set to an empty string. A null value + * will use the system default value (0 / None). + * 0 = None, 1 = Any face, 2 = Any fingerprint, 3 = Under display fingerprint * @hide */ - @Readable - public static final String TV_INPUT_HIDDEN_INPUTS = "tv_input_hidden_inputs"; + public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED = + "active_unlock_on_unlock_intent_when_biometric_enrolled"; /** - * List of custom TV input labels. This is a string containing - * pairs. TV input id and custom name are encoded by {@link android.net.Uri#encode(String)} - * and separated by ','. Each pair is separated by ':'. + * If active unlock triggers on unlock intents, then also request active unlock on + * these wake-up reasons. See {@link PowerManager.WakeReason} for value mappings. + * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this + * setting should be disabled, then this should be set to an empty string. A null value + * will use the system default value (WAKE_REASON_UNFOLD_DEVICE). * @hide */ - @Readable - public static final String TV_INPUT_CUSTOM_LABELS = "tv_input_custom_labels"; + public static final String ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS = + "active_unlock_wakeups_considered_unlock_intents"; /** - * Whether TV app uses non-system inputs. - * - *

- * The value is boolean (1 or 0), where 1 means non-system TV inputs are allowed, - * and 0 means non-system TV inputs are not allowed. - * - *

- * Devices such as sound bars may have changed the system property allow_third_party_inputs - * to false so the TV Application only uses HDMI and other built in inputs. This setting - * allows user to override the default and have the TV Application use third party TV inputs - * available on play store. - * + * If active unlock triggers and succeeds on these wakeups, force dismiss keyguard on + * these wake reasons. See {@link PowerManager#WakeReason} for value mappings. + * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this + * setting should be disabled, then this should be set to an empty string. A null value + * will use the system default value (WAKE_REASON_UNFOLD_DEVICE). * @hide */ - @Readable - public static final String TV_APP_USES_NON_SYSTEM_INPUTS = "tv_app_uses_non_system_inputs"; + public static final String ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD = + "active_unlock_wakeups_to_force_dismiss_keyguard"; /** - * Whether automatic routing of system audio to USB audio peripheral is disabled. - * The value is boolean (1 or 0), where 1 means automatic routing is disabled, - * and 0 means automatic routing is enabled. + * Whether the assist gesture should be enabled. * * @hide */ @Readable - public static final String USB_AUDIO_AUTOMATIC_ROUTING_DISABLED = - "usb_audio_automatic_routing_disabled"; + public static final String ASSIST_GESTURE_ENABLED = "assist_gesture_enabled"; /** - * The timeout in milliseconds before the device fully goes to sleep after - * a period of inactivity. This value sets an upper bound on how long the device - * will stay awake or dreaming without user activity. It should generally - * be longer than {@link Settings.System#SCREEN_OFF_TIMEOUT} as otherwise the device - * will sleep before it ever has a chance to dream. - *

- * Use -1 to disable this timeout. - *

+ * Sensitivity control for the assist gesture. * * @hide */ @Readable - public static final String SLEEP_TIMEOUT = "sleep_timeout"; + public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity"; /** - * The timeout in milliseconds before the device goes to sleep due to user inattentiveness, - * even if the system is holding wakelocks. It should generally be longer than {@code - * config_attentiveWarningDuration}, as otherwise the device will show the attentive - * warning constantly. Small timeouts are discouraged, as they will cause the device to - * go to sleep quickly after waking up. - *

- * Use -1 to disable this timeout. - *

+ * Whether the assist gesture should silence alerts. * * @hide */ @Readable - public static final String ATTENTIVE_TIMEOUT = "attentive_timeout"; + public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED = + "assist_gesture_silence_alerts_enabled"; /** - * Controls whether double tap to wake is enabled. + * Whether the assist gesture should wake the phone. + * * @hide */ @Readable - public static final String DOUBLE_TAP_TO_WAKE = "double_tap_to_wake"; + public static final String ASSIST_GESTURE_WAKE_ENABLED = + "assist_gesture_wake_enabled"; /** - * Controls whether double tap to sleep is enabled. + * Indicates whether the Assist Gesture Deferred Setup has been completed. + *

+ * Type: int (0 for false, 1 for true) + * * @hide */ - public static final String DOUBLE_TAP_TO_SLEEP = "double_tap_to_sleep"; + @SystemApi + @Readable + public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete"; /** - * The current assistant component. It could be a voice interaction service, - * or an activity that handles ACTION_ASSIST, or empty which means using the default - * handling. - * - *

This should be set indirectly by setting the {@link - * android.app.role.RoleManager#ROLE_ASSISTANT assistant role}. + * Whether the assistant can be triggered by a touch gesture. * * @hide */ - @UnsupportedAppUsage - @Readable - public static final String ASSISTANT = "assistant"; + public static final String ASSIST_TOUCH_GESTURE_ENABLED = + "assist_touch_gesture_enabled"; /** - * Whether the camera launch gesture should be disabled. + * Whether the assistant can be triggered by long-pressing the home button * * @hide */ - @Readable - public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled"; + public static final String ASSIST_LONG_PRESS_HOME_ENABLED = + "assist_long_press_home_enabled"; /** - * Whether the emergency gesture should be enabled. + * Whether all entrypoints (e.g. long-press home, long-press nav handle) + * can trigger contextual search. * * @hide */ - public static final String EMERGENCY_GESTURE_ENABLED = "emergency_gesture_enabled"; + public static final String SEARCH_ALL_ENTRYPOINTS_ENABLED = + "search_all_entrypoints_enabled"; /** - * Whether the emergency gesture sound should be enabled. - * + * Whether or not the accessibility data streaming is enbled for the + * {@link VisualQueryDetectedResult#setAccessibilityDetectionData}. * @hide */ - public static final String EMERGENCY_GESTURE_SOUND_ENABLED = - "emergency_gesture_sound_enabled"; + public static final String VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED = + "visual_query_accessibility_detection_enabled"; /** - * Whether the emergency gesture UI is currently showing. + * Timeout to be used for unbinding to the configured remote + * {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService} if there are no + * requests in the queue. A value of -1 represents to never unbind. * * @hide */ - public static final String EMERGENCY_GESTURE_UI_SHOWING = "emergency_gesture_ui_showing"; + public static final String ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS = + "on_device_intelligence_unbind_timeout_ms"; + /** - * The last time the emergency gesture UI was started. + * Timeout that represents maximum idle time before which a callback should be populated. * * @hide */ - public static final String EMERGENCY_GESTURE_UI_LAST_STARTED_MILLIS = - "emergency_gesture_ui_last_started_millis"; + public static final String ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS = + "on_device_intelligence_idle_timeout_ms"; /** - * Whether double tap the power button gesture is enabled. + * Timeout to be used for unbinding to the configured remote + * {@link android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService} if there + * are no requests in the queue. A value of -1 represents to never unbind. * * @hide */ - @Readable - public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED = - "double_tap_power_button_gesture_enabled"; + public static final String ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS = + "on_device_inference_unbind_timeout_ms"; /** - * Double tap power button gesture behavior. - * 0 = Camera launch - * 1 = Wallet launch + * Control whether Night display is currently activated. * @hide */ @Readable - public static final String DOUBLE_TAP_POWER_BUTTON_GESTURE = - "double_tap_power_button_gesture"; + public static final String NIGHT_DISPLAY_ACTIVATED = "night_display_activated"; /** - * Whether the camera launch gesture to double tap the power button when the screen is off - * should be disabled. - * + * Control whether Night display will automatically activate/deactivate. * @hide */ @Readable - public static final String CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED = - "camera_double_tap_power_gesture_disabled"; + public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode"; /** - * Whether the camera double twist gesture to flip between front and back mode should be - * enabled. - * + * Control the color temperature of Night Display, represented in Kelvin. * @hide */ @Readable - public static final String CAMERA_DOUBLE_TWIST_TO_FLIP_ENABLED = - "camera_double_twist_to_flip_enabled"; + public static final String NIGHT_DISPLAY_COLOR_TEMPERATURE = + "night_display_color_temperature"; /** - * Whether or not the smart camera lift trigger that launches the camera when the user moves - * the phone into a position for taking photos should be enabled. - * + * Custom time when Night display is scheduled to activate. + * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). * @hide */ @Readable - public static final String CAMERA_LIFT_TRIGGER_ENABLED = "camera_lift_trigger_enabled"; + public static final String NIGHT_DISPLAY_CUSTOM_START_TIME = + "night_display_custom_start_time"; /** - * The default enable state of the camera lift trigger. - * + * Custom time when Night display is scheduled to deactivate. + * Represented as milliseconds from midnight (e.g. 21600000 == 6am). * @hide */ - public static final int CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT = 1; + @Readable + public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time"; /** - * Whether or not the flashlight (camera torch mode) is available required to turn - * on flashlight. - * + * A String representing the LocalDateTime when Night display was last activated. Use to + * decide whether to apply the current activated state after a reboot or user change. In + * legacy cases, this is represented by the time in milliseconds (since epoch). * @hide */ @Readable - public static final String FLASHLIGHT_AVAILABLE = "flashlight_available"; + public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME = + "night_display_last_activated_time"; /** - * Whether or not flashlight is enabled. - * + * Control display engine mode. * @hide */ - @Readable - public static final String FLASHLIGHT_ENABLED = "flashlight_enabled"; + public static final String DISPLAY_ENGINE_MODE = "display_engine_mode"; /** - * Whether or not face unlock is allowed on Keyguard. + * Control whether display white balance is currently enabled. * @hide */ @Readable - public static final String FACE_UNLOCK_KEYGUARD_ENABLED = "face_unlock_keyguard_enabled"; + public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled"; /** - * Whether or not face unlock dismisses the keyguard. + * Used by DisplayManager to backup/restore the user-selected resolution mode. * @hide */ @Readable - public static final String FACE_UNLOCK_DISMISSES_KEYGUARD = - "face_unlock_dismisses_keyguard"; + public static final String SCREEN_RESOLUTION_MODE = "screen_resolution_mode"; /** - * Whether or not media is shown automatically when bypassing as a heads up. + * Resolution Mode Constants for SCREEN_RESOLUTION_MODE setting. + * * @hide */ - @Readable - public static final String SHOW_MEDIA_WHEN_BYPASSING = - "show_media_when_bypassing"; + @IntDef(prefix = { "RESOLUTION_MODE_" }, value = { + RESOLUTION_MODE_UNKNOWN, + RESOLUTION_MODE_HIGH, + RESOLUTION_MODE_FULL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ResolutionMode {} + /** @hide */ + public static final int RESOLUTION_MODE_UNKNOWN = 0; + /** @hide */ + public static final int RESOLUTION_MODE_HIGH = 1; + /** @hide */ + public static final int RESOLUTION_MODE_FULL = 2; /** - * Whether or not face unlock requires attention. This is a cached value, the source of - * truth is obtained through the HAL. + * Names of the service components that the current user has explicitly allowed to + * be a VR mode listener, separated by ':'. + * * @hide */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi @Readable - public static final String FACE_UNLOCK_ATTENTION_REQUIRED = - "face_unlock_attention_required"; + public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners"; /** - * Whether or not face unlock requires a diverse set of poses during enrollment. This is a - * cached value, the source of truth is obtained through the HAL. + * Behavior of the display while in VR mode. + * + * One of {@link #VR_DISPLAY_MODE_LOW_PERSISTENCE} or {@link #VR_DISPLAY_MODE_OFF}. + * * @hide */ @Readable - public static final String FACE_UNLOCK_DIVERSITY_REQUIRED = - "face_unlock_diversity_required"; - + public static final String VR_DISPLAY_MODE = "vr_display_mode"; /** - * Whether or not face unlock is allowed for apps (through BiometricPrompt). - * @hide + * Lower the display persistence while the system is in VR mode. + * + * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE + * + * @hide. */ - @Readable - public static final String FACE_UNLOCK_APP_ENABLED = "face_unlock_app_enabled"; + public static final int VR_DISPLAY_MODE_LOW_PERSISTENCE = 0; /** - * Whether or not face unlock always requires user confirmation, meaning {@link - * android.hardware.biometrics.BiometricPrompt.Builder#setConfirmationRequired(boolean)} - * is always 'true'. This overrides the behavior that apps choose in the - * setConfirmationRequired API. - * @hide - */ - @Readable - public static final String FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION = - "face_unlock_always_require_confirmation"; + * Do not alter the display persistence while the system is in VR mode. + * + * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE + * + * @hide. + */ + public static final int VR_DISPLAY_MODE_OFF = 1; /** - * Whether or not a user should re enroll their face. + * The latest SDK version that CarrierAppUtils#disableCarrierAppsUntilPrivileged has been + * executed for. * - * Face unlock re enroll. - * 0 = No re enrollment. - * 1 = Re enrollment is required. + *

This is used to ensure that we only take one pass which will disable apps that are not + * privileged (if any). From then on, we only want to enable apps (when a matching SIM is + * inserted), to avoid disabling an app that the user might actively be using. + * + *

Will be set to {@link android.os.Build.VERSION#SDK_INT} once executed. Note that older + * SDK versions prior to R set 1 for this value. * * @hide */ @Readable - public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll"; + public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled"; /** - * The time (in millis) to wait for a power button before sending a - * successful auth in to keyguard(for side fingerprint) + * Whether parent user can access remote contact in managed profile. + * * @hide */ @Readable - public static final String FINGERPRINT_SIDE_FPS_KG_POWER_WINDOW = - "fingerprint_side_fps_kg_power_window"; + public static final String MANAGED_PROFILE_CONTACT_REMOTE_SEARCH = + "managed_profile_contact_remote_search"; /** - * The time (in millis) to wait for a power button before sending - * a successful auth in biometric prompt(for side fingerprint) + * Whether parent profile can access remote calendar data in managed profile. + * * @hide */ @Readable - public static final String FINGERPRINT_SIDE_FPS_BP_POWER_WINDOW = - "fingerprint_side_fps_bp_power_window"; + public static final String CROSS_PROFILE_CALENDAR_ENABLED = + "cross_profile_calendar_enabled"; /** - * The time (in millis) that a finger tap will wait for a power button - * before dismissing the power dialog during enrollment(for side - * fingerprint) + * Whether or not the automatic storage manager is enabled and should run on the device. + * * @hide */ @Readable - public static final String FINGERPRINT_SIDE_FPS_ENROLL_TAP_WINDOW = - "fingerprint_side_fps_enroll_tap_window"; + public static final String AUTOMATIC_STORAGE_MANAGER_ENABLED = + "automatic_storage_manager_enabled"; /** - * The time (in millis) that a power event will ignore future authentications - * (for side fingerprint) + * How many days of information for the automatic storage manager to retain on the device. + * * @hide */ @Readable - public static final String FINGERPRINT_SIDE_FPS_AUTH_DOWNTIME = - "fingerprint_side_fps_auth_downtime"; + public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN = + "automatic_storage_manager_days_to_retain"; /** - * Whether or not a SFPS device is enabling the performant auth setting. - * The "_V2" suffix was added to re-introduce the default behavior for - * users. See b/265264294 fore more details. + * Default number of days of information for the automatic storage manager to retain. + * * @hide */ - public static final String SFPS_PERFORMANT_AUTH_ENABLED = "sfps_performant_auth_enabled_v2"; + public static final int AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT = 90; /** - * Whether or not the UDFPS device is enabling the screen off unlock settings. + * How many bytes the automatic storage manager has cleared out. + * * @hide */ - @TestApi @Readable - @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi without associated feature - public static final String SCREEN_OFF_UNLOCK_UDFPS_ENABLED = "screen_off_udfps_enabled"; + public static final String AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED = + "automatic_storage_manager_bytes_cleared"; /** - * Whether or not debugging is enabled. + * Last run time for the automatic storage manager. + * * @hide */ @Readable - public static final String BIOMETRIC_DEBUG_ENABLED = - "biometric_debug_enabled"; - + public static final String AUTOMATIC_STORAGE_MANAGER_LAST_RUN = + "automatic_storage_manager_last_run"; /** - * Whether or not both fingerprint and face virtual sensors are enabled. + * If the automatic storage manager has been disabled by policy. Note that this doesn't + * mean that the automatic storage manager is prevented from being re-enabled -- this only + * means that it was turned off by policy at least once. + * * @hide */ - @TestApi @Readable - public static final String BIOMETRIC_VIRTUAL_ENABLED = "biometric_virtual_enabled"; + public static final String AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY = + "automatic_storage_manager_turned_off_by_policy"; /** - * Whether or not fingerprint virtual sensors are enabled. + * Whether SystemUI navigation keys is enabled. * @hide */ - @FlaggedApi("com.android.server.biometrics.face_vhal_feature") - public static final String BIOMETRIC_FINGERPRINT_VIRTUAL_ENABLED = - "biometric_fingerprint_virtual_enabled"; + @Readable + public static final String SYSTEM_NAVIGATION_KEYS_ENABLED = + "system_navigation_keys_enabled"; /** - * Whether or not face virtual sensors are enabled. + * Holds comma separated list of ordering of QS tiles. + * * @hide */ - @FlaggedApi("com.android.server.biometrics.face_vhal_feature") - public static final String BIOMETRIC_FACE_VIRTUAL_ENABLED = - "biometric_face_virtual_enabled"; + @Readable(maxTargetSdk = VERSION_CODES.TIRAMISU) + public static final String QS_TILES = "sysui_qs_tiles"; /** - * Whether or not biometric is allowed on Keyguard. + * Whether this user has enabled Quick controls. * - * @deprecated Use {@link #FINGERPRINT_KEYGUARD_ENABLED} or {@link #FACE_KEYGUARD_ENABLED} - * instead. + * 0 indicates disabled and 1 indicates enabled. A non existent value should be treated as + * enabled. * + * @deprecated Controls are migrated to Quick Settings, rendering this unnecessary and will + * be removed in a future release. * @hide */ - @Deprecated @Readable - public static final String BIOMETRIC_KEYGUARD_ENABLED = "biometric_keyguard_enabled"; + @Deprecated + public static final String CONTROLS_ENABLED = "controls_enabled"; /** - * Whether or not biometric is allowed for apps (through BiometricPrompt). - * - * @deprecated Use {@link #FINGERPRINT_APP_ENABLED} or {@link #FACE_APP_ENABLED} instead. + * Whether power menu content (cards, passes, controls) will be shown when device is locked. * + * 0 indicates hide and 1 indicates show. A non existent value will be treated as hide. * @hide */ - @Deprecated + @TestApi @Readable - public static final String BIOMETRIC_APP_ENABLED = "biometric_app_enabled"; + public static final String POWER_MENU_LOCKED_SHOW_CONTENT = + "power_menu_locked_show_content"; /** - * Whether or not fingerprint is allowed on Keyguard. + * Whether home controls should be accessible from the lockscreen + * * @hide */ - @Readable - public static final String FINGERPRINT_KEYGUARD_ENABLED = "fingerprint_keyguard_enabled"; + public static final String LOCKSCREEN_SHOW_CONTROLS = "lockscreen_show_controls"; /** - * Whether or not fingerprint is allowed for apps (through BiometricPrompt). + * Whether trivial home controls can be used without authentication + * * @hide */ - @Readable - public static final String FINGERPRINT_APP_ENABLED = "fingerptint_app_enabled"; + public static final String LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS = + "lockscreen_allow_trivial_controls"; /** - * Whether or not face is allowed on Keyguard. + * Whether wallet should be accessible from the lockscreen + * * @hide */ - @Readable - public static final String FACE_KEYGUARD_ENABLED = "face_keyguard_enabled"; + public static final String LOCKSCREEN_SHOW_WALLET = "lockscreen_show_wallet"; /** - * Whether or not face is allowed for apps (through BiometricPrompt). + * Whether to use the lockscreen double-line clock + * * @hide */ - @Readable - public static final String FACE_APP_ENABLED = "face_app_enabled"; + public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK = + "lockscreen_use_double_line_clock"; /** - * Whether or not mandatory biometrics is enabled. + * Whether to show the vibrate icon in the Status Bar (default off) + * * @hide */ - public static final String MANDATORY_BIOMETRICS = "mandatory_biometrics"; + public static final String STATUS_BAR_SHOW_VIBRATE_ICON = "status_bar_show_vibrate_icon"; /** - * Whether or not requirements for mandatory biometrics is satisfied. + * Specifies whether the web action API is enabled. + * * @hide */ - public static final String MANDATORY_BIOMETRICS_REQUIREMENTS_SATISFIED = - "mandatory_biometrics_requirements_satisfied"; + @SystemApi + @Readable + public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled"; /** - * Whether or not active unlock triggers on wake. + * Whether qr code scanner should be accessible from the lockscreen + * * @hide */ - public static final String ACTIVE_UNLOCK_ON_WAKE = "active_unlock_on_wake"; + public static final String LOCK_SCREEN_SHOW_QR_CODE_SCANNER = + "lock_screen_show_qr_code_scanner"; /** - * Whether or not active unlock triggers on unlock intent. + * Whether or not to enable qr code code scanner setting to enable/disable lockscreen + * entry point. Any value apart from null means setting needs to be enabled + * * @hide */ - public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT = - "active_unlock_on_unlock_intent"; + public static final String SHOW_QR_CODE_SCANNER_SETTING = + "show_qr_code_scanner_setting"; /** - * Whether or not active unlock triggers on biometric failure. + * Has this pairable device been paired or upgraded from a previously paired system. * @hide */ - public static final String ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL = - "active_unlock_on_biometric_fail"; + @Readable + public static final String DEVICE_PAIRED = "device_paired"; /** - * Whether or not active unlock triggers on legacy unlock intents. + * Specifies additional package name for broadcasting the CMAS messages. * @hide */ - public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_LEGACY = - "active_unlock_on_unlock_intent_legacy"; + @Readable + public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg"; /** - * If active unlock triggers on biometric failures, include the following error codes - * as a biometric failure. See {@link android.hardware.biometrics.BiometricFaceConstants}. - * Error codes should be separated by a pipe. For example: "1|4|5". If active unlock - * should never trigger on any face errors, this should be set to an empty string. - * A null value will use the system default value (TIMEOUT). + * Whether the launcher should show any notification badges. + * The value is boolean (1 or 0). * @hide */ - public static final String ACTIVE_UNLOCK_ON_FACE_ERRORS = - "active_unlock_on_face_errors"; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @TestApi + @Readable + public static final String NOTIFICATION_BADGING = "notification_badging"; /** - * If active unlock triggers on biometric failures, include the following acquired info - * as a "biometric failure". See {@link android.hardware.biometrics.BiometricFaceConstants}. - * Acquired codes should be separated by a pipe. For example: "1|4|5". If active unlock - * should never on trigger on any acquired info messages, this should be - * set to an empty string. A null value will use the system default value (none). + * When enabled the system will maintain a rolling history of received notifications. When + * disabled the history will be disabled and deleted. + * + * The value 1 - enable, 0 - disable * @hide */ - public static final String ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO = - "active_unlock_on_face_acquire_info"; + @Readable + public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled"; /** - * If active unlock triggers on biometric failures, then also request active unlock on - * unlock intent when each setting (BiometricType) is the only biometric type enrolled. - * Biometric types should be separated by a pipe. For example: "0|3" or "0". If this - * setting should be disabled, then this should be set to an empty string. A null value - * will use the system default value (0 / None). - * 0 = None, 1 = Any face, 2 = Any fingerprint, 3 = Under display fingerprint + * When enabled conversations marked as favorites will be set to bubble. + * + * The value 1 - enable, 0 - disable * @hide */ - public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED = - "active_unlock_on_unlock_intent_when_biometric_enrolled"; + @Readable + public static final String BUBBLE_IMPORTANT_CONVERSATIONS + = "bubble_important_conversations"; /** - * If active unlock triggers on unlock intents, then also request active unlock on - * these wake-up reasons. See {@link PowerManager.WakeReason} for value mappings. - * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this - * setting should be disabled, then this should be set to an empty string. A null value - * will use the system default value (WAKE_REASON_UNFOLD_DEVICE). + * When enabled, notifications able to bubble will display an affordance allowing the user + * to bubble them. + * The value is boolean (1 to enable or 0 to disable). + * * @hide */ - public static final String ACTIVE_UNLOCK_WAKEUPS_CONSIDERED_UNLOCK_INTENTS = - "active_unlock_wakeups_considered_unlock_intents"; + @TestApi + @SuppressLint("NoSettingsProvider") + @Readable + public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; /** - * If active unlock triggers and succeeds on these wakeups, force dismiss keyguard on - * these wake reasons. See {@link PowerManager#WakeReason} for value mappings. - * WakeReasons should be separated by a pipe. For example: "0|3" or "0". If this - * setting should be disabled, then this should be set to an empty string. A null value - * will use the system default value (WAKE_REASON_UNFOLD_DEVICE). + * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right + * swipe). + * * @hide */ - public static final String ACTIVE_UNLOCK_WAKEUPS_TO_FORCE_DISMISS_KEYGUARD = - "active_unlock_wakeups_to_force_dismiss_keyguard"; + @Readable + public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl"; /** - * Whether the assist gesture should be enabled. - * + * Comma separated list of QS tiles that have been auto-added already. * @hide */ @Readable - public static final String ASSIST_GESTURE_ENABLED = "assist_gesture_enabled"; + public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles"; /** - * Sensitivity control for the assist gesture. - * + * The duration of timeout, in milliseconds, to switch from a non-Dock User to the + * Dock User when the device is docked. * @hide */ - @Readable - public static final String ASSIST_GESTURE_SENSITIVITY = "assist_gesture_sensitivity"; + public static final String TIMEOUT_TO_DOCK_USER = "timeout_to_dock_user"; /** - * Whether the assist gesture should silence alerts. + * Backup manager behavioral parameters. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "key_value_backup_interval_milliseconds=14400000,key_value_backup_require_charging=true" + * + * The following keys are supported: + * + *

+         * key_value_backup_interval_milliseconds  (long)
+         * key_value_backup_fuzz_milliseconds      (long)
+         * key_value_backup_require_charging       (boolean)
+         * key_value_backup_required_network_type  (int)
+         * full_backup_interval_milliseconds       (long)
+         * full_backup_require_charging            (boolean)
+         * full_backup_required_network_type       (int)
+         * backup_finished_notification_receivers  (String[])
+         * 
+ * + * backup_finished_notification_receivers uses ":" as delimiter for values. * + *

+ * Type: string * @hide */ @Readable - public static final String ASSIST_GESTURE_SILENCE_ALERTS_ENABLED = - "assist_gesture_silence_alerts_enabled"; + public static final String BACKUP_MANAGER_CONSTANTS = "backup_manager_constants"; + /** - * Whether the assist gesture should wake the phone. + * Local transport parameters so we can configure it for tests. + * This is encoded as a key=value list, separated by commas. + * + * The following keys are supported: + * + *

+         * fake_encryption_flag  (boolean)
+         * 
* + *

+ * Type: string * @hide */ @Readable - public static final String ASSIST_GESTURE_WAKE_ENABLED = - "assist_gesture_wake_enabled"; + public static final String BACKUP_LOCAL_TRANSPORT_PARAMETERS = + "backup_local_transport_parameters"; /** - * Indicates whether the Assist Gesture Deferred Setup has been completed. - *

- * Type: int (0 for false, 1 for true) - * + * Flag to set if the system should predictively attempt to re-enable Bluetooth while + * the user is driving. * @hide */ - @SystemApi @Readable - public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete"; + public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving"; /** - * Whether the assistant can be triggered by a touch gesture. - * + * Volume dialog timeout in ms. * @hide */ - public static final String ASSIST_TOUCH_GESTURE_ENABLED = - "assist_touch_gesture_enabled"; + public static final String VOLUME_DIALOG_DISMISS_TIMEOUT = "volume_dialog_dismiss_timeout"; /** - * Whether the assistant can be triggered by long-pressing the home button - * + * Volume dialog haptic feedback * @hide */ - public static final String ASSIST_LONG_PRESS_HOME_ENABLED = - "assist_long_press_home_enabled"; + public static final String VOLUME_DIALOG_HAPTIC_FEEDBACK = "volume_dialog_haptic_feedback"; /** - * Whether all entrypoints (e.g. long-press home, long-press nav handle) - * can trigger contextual search. + * What behavior should be invoked when the volume hush gesture is triggered + * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE, VOLUME_HUSH_CYCLE. * * @hide */ - public static final String SEARCH_ALL_ENTRYPOINTS_ENABLED = - "search_all_entrypoints_enabled"; + @SystemApi + @Readable + public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture"; + + /** @hide */ + @SystemApi + public static final int VOLUME_HUSH_OFF = 0; + /** @hide */ + @SystemApi + public static final int VOLUME_HUSH_VIBRATE = 1; + /** @hide */ + @SystemApi + public static final int VOLUME_HUSH_MUTE = 2; + /** @hide */ + public static final int VOLUME_HUSH_CYCLE = 3; /** - * Whether or not the accessibility data streaming is enbled for the - * {@link VisualQueryDetectedResult#setAccessibilityDetectionData}. + * The number of times (integer) the user has manually enabled battery saver. * @hide */ - public static final String VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED = - "visual_query_accessibility_detection_enabled"; + @Readable + public static final String LOW_POWER_MANUAL_ACTIVATION_COUNT = + "low_power_manual_activation_count"; /** - * Timeout to be used for unbinding to the configured remote - * {@link android.service.ondeviceintelligence.OnDeviceIntelligenceService} if there are no - * requests in the queue. A value of -1 represents to never unbind. + * Whether the "first time battery saver warning" dialog needs to be shown (0: default) + * or not (1). * * @hide */ - public static final String ON_DEVICE_INTELLIGENCE_UNBIND_TIMEOUT_MS = - "on_device_intelligence_unbind_timeout_ms"; - + @Readable + public static final String LOW_POWER_WARNING_ACKNOWLEDGED = + "low_power_warning_acknowledged"; /** - * Timeout that represents maximum idle time before which a callback should be populated. + * Whether the "first time extra battery saver warning" dialog needs to be shown + * (0: default) or not (1). * * @hide */ - public static final String ON_DEVICE_INTELLIGENCE_IDLE_TIMEOUT_MS = - "on_device_intelligence_idle_timeout_ms"; + public static final String EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED = + "extra_low_power_warning_acknowledged"; /** - * Timeout to be used for unbinding to the configured remote - * {@link android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService} if there - * are no requests in the queue. A value of -1 represents to never unbind. + * Whether the emergency thermal alert would be disabled + * (0: default) or not (1). * * @hide */ - public static final String ON_DEVICE_INFERENCE_UNBIND_TIMEOUT_MS = - "on_device_inference_unbind_timeout_ms"; + public static final String EMERGENCY_THERMAL_ALERT_DISABLED = + "emergency_thermal_alert_disabled"; /** - * Control whether Night display is currently activated. + * 0 (default) Auto battery saver suggestion has not been suppressed. 1) it has been + * suppressed. * @hide */ @Readable - public static final String NIGHT_DISPLAY_ACTIVATED = "night_display_activated"; + public static final String SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION = + "suppress_auto_battery_saver_suggestion"; /** - * Control whether Night display will automatically activate/deactivate. + * List of packages, which data need to be unconditionally cleared before full restore. + * Type: string * @hide */ @Readable - public static final String NIGHT_DISPLAY_AUTO_MODE = "night_display_auto_mode"; + public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE = + "packages_to_clear_data_before_full_restore"; /** - * Control the color temperature of Night Display, represented in Kelvin. + * How often to check for location access. * @hide + * + * @deprecated This has been moved to DeviceConfig property + * {@link LocationAccessCheck#PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS} in a T + * module update + * + * Before Android T set this property to control the interval for the check + * On Android T set this and the DeviceConfig property + * After Android T set the DeviceConfig property */ + @SystemApi + @Deprecated @Readable - public static final String NIGHT_DISPLAY_COLOR_TEMPERATURE = - "night_display_color_temperature"; + public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = + "location_access_check_interval_millis"; /** - * Custom time when Night display is scheduled to activate. - * Represented as milliseconds from midnight (e.g. 79200000 == 10pm). + * Delay between granting location access and checking it. * @hide + * + * @deprecated This has been moved to DeviceConfig property + * {@link LocationAccessCheck#PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS} in a T module + * update + * + * Before Android T set this property to control the delay for the check + * On Android T set this and the DeviceConfig property + * After Android T set the DeviceConfig property */ + @SystemApi + @Deprecated @Readable - public static final String NIGHT_DISPLAY_CUSTOM_START_TIME = - "night_display_custom_start_time"; + public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = + "location_access_check_delay_millis"; /** - * Custom time when Night display is scheduled to deactivate. - * Represented as milliseconds from midnight (e.g. 21600000 == 6am). + * @deprecated This setting does not have any effect anymore * @hide */ + @SystemApi + @Deprecated @Readable - public static final String NIGHT_DISPLAY_CUSTOM_END_TIME = "night_display_custom_end_time"; + public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = + "location_permissions_upgrade_to_q_mode"; /** - * A String representing the LocalDateTime when Night display was last activated. Use to - * decide whether to apply the current activated state after a reboot or user change. In - * legacy cases, this is represented by the time in milliseconds (since epoch). + * Whether or not the system Auto Revoke feature is disabled. * @hide */ + @SystemApi @Readable - public static final String NIGHT_DISPLAY_LAST_ACTIVATED_TIME = - "night_display_last_activated_time"; + public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled"; /** - * Control whether display white balance is currently enabled. + * Map of android.theme.customization.* categories to the enabled overlay package for that + * category, formatted as a serialized {@link org.json.JSONObject}. If there is no + * corresponding package included for a category, then all overlay packages in that + * category must be disabled. + * + * A few category keys have special meaning and are used for Material You theming. + * + * A {@code FabricatedOverlay} containing Material You tonal palettes will be generated + * in case {@code android.theme.customization.system_palette} contains a + * {@link android.annotation.ColorInt}. + * + * The strategy used for generating the tonal palettes can be defined with the + * {@code android.theme.customization.theme_style} key, with one of the following options: + *

    + *
  • {@code TONAL_SPOT} is a mid vibrancy palette that uses an accent 3 analogous to + * accent 1.
  • + *
  • {@code VIBRANT} is a high vibrancy palette that harmoniously blends subtle shifts + * between colors.
  • + *
  • {@code EXPRESSIVE} is a high vibrancy palette that pairs unexpected and unique + * accents colors together.
  • + *
  • {@code SPRITZ} is a low vibrancy palette that creates a soft wash between + * colors.
  • + *
  • {@code RAINBOW} uses both chromatic accents and neutral surfaces to create a more + * subtle color experience for users.
  • + *
  • {@code FRUIT_SALAD} experiments with the concept of "two tone colors" to give + * users more expression.
  • + *
+ * + * Example of valid fabricated theme specification: + *
+         * {
+         *     "android.theme.customization.system_palette":"B1611C",
+         *     "android.theme.customization.theme_style":"EXPRESSIVE"
+         * }
+         * 
* @hide */ + @SystemApi @Readable - public static final String DISPLAY_WHITE_BALANCE_ENABLED = "display_white_balance_enabled"; + public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = + "theme_customization_overlay_packages"; /** - * Used by DisplayManager to backup/restore the user-selected resolution mode. + * Indicates whether the nav bar is forced to always be visible, even in immersive mode. + *

Type: int (0 for false, 1 for true) + * * @hide */ - @Readable - public static final String SCREEN_RESOLUTION_MODE = "screen_resolution_mode"; + public static final String NAV_BAR_FORCE_VISIBLE = "nav_bar_force_visible"; /** - * Resolution Mode Constants for SCREEN_RESOLUTION_MODE setting. + * Indicates whether the device is in kids nav mode. + *

Type: int (0 for false, 1 for true) * * @hide */ - @IntDef(prefix = { "RESOLUTION_MODE_" }, value = { - RESOLUTION_MODE_UNKNOWN, - RESOLUTION_MODE_HIGH, - RESOLUTION_MODE_FULL - }) - @Retention(RetentionPolicy.SOURCE) - public @interface ResolutionMode {} - /** @hide */ - public static final int RESOLUTION_MODE_UNKNOWN = 0; - /** @hide */ - public static final int RESOLUTION_MODE_HIGH = 1; - /** @hide */ - public static final int RESOLUTION_MODE_FULL = 2; + public static final String NAV_BAR_KIDS_MODE = "nav_bar_kids_mode"; /** - * Names of the service components that the current user has explicitly allowed to - * be a VR mode listener, separated by ':'. - * + * This defines the order in which the 3-button navigation bar's buttons are displayed. + * 0 = left-to-right (back, home, recent) + * 1 = right-to-left (recent, home, back) + * @hide + */ + public static final String NAVIGATIONBAR_KEY_ORDER = "navigationbar_key_order"; + + /** + * Navigation bar mode. + * 0 = 3 button + * 1 = 2 button + * 2 = fully gestural * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi @Readable - public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners"; + public static final String NAVIGATION_MODE = + "navigation_mode"; /** - * Behavior of the display while in VR mode. - * - * One of {@link #VR_DISPLAY_MODE_LOW_PERSISTENCE} or {@link #VR_DISPLAY_MODE_OFF}. - * + * The value is from another(source) device's {@link #NAVIGATION_MODE} during restore. + * It's supposed to be written only by + * {@link com.android.providers.settings.SettingsHelper}. + * This setting should not be added into backup array. + *

Value: -1 = Can't get value from restore(default), + * 0 = 3 button, + * 1 = 2 button, + * 2 = fully gestural. * @hide */ - @Readable - public static final String VR_DISPLAY_MODE = "vr_display_mode"; + public static final String NAVIGATION_MODE_RESTORE = "navigation_mode_restore"; /** - * Lower the display persistence while the system is in VR mode. - * - * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE - * - * @hide. + * Scale factor for the back gesture inset size on the left side of the screen. + * @hide */ - public static final int VR_DISPLAY_MODE_LOW_PERSISTENCE = 0; + @Readable + public static final String BACK_GESTURE_INSET_SCALE_LEFT = + "back_gesture_inset_scale_left"; /** - * Do not alter the display persistence while the system is in VR mode. - * - * @see PackageManager#FEATURE_VR_MODE_HIGH_PERFORMANCE - * - * @hide. + * Scale factor for the back gesture inset size on the right side of the screen. + * @hide */ - public static final int VR_DISPLAY_MODE_OFF = 1; + @Readable + public static final String BACK_GESTURE_INSET_SCALE_RIGHT = + "back_gesture_inset_scale_right"; /** - * The latest SDK version that CarrierAppUtils#disableCarrierAppsUntilPrivileged has been - * executed for. - * - *

This is used to ensure that we only take one pass which will disable apps that are not - * privileged (if any). From then on, we only want to enable apps (when a matching SIM is - * inserted), to avoid disabling an app that the user might actively be using. - * - *

Will be set to {@link android.os.Build.VERSION#SDK_INT} once executed. Note that older - * SDK versions prior to R set 1 for this value. - * + * Current provider of proximity-based sharing services. + * Default value in @string/config_defaultNearbySharingComponent. + * No VALIDATOR as this setting will not be backed up. * @hide */ @Readable - public static final String CARRIER_APPS_HANDLED = "carrier_apps_handled"; + public static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component"; /** - * Whether parent user can access remote contact in managed profile. - * + * Nearby Sharing Slice URI for the SliceProvider to + * read Nearby Sharing scan results and then draw the UI. * @hide */ - @Readable - public static final String MANAGED_PROFILE_CONTACT_REMOTE_SEARCH = - "managed_profile_contact_remote_search"; + public static final String NEARBY_SHARING_SLICE_URI = "nearby_sharing_slice_uri"; /** - * Whether parent profile can access remote calendar data in managed profile. - * + * Current provider of Fast Pair saved devices page. + * Default value in @string/config_defaultNearbyFastPairSettingsDevicesComponent. + * No VALIDATOR as this setting will not be backed up. * @hide */ - @Readable - public static final String CROSS_PROFILE_CALENDAR_ENABLED = - "cross_profile_calendar_enabled"; + public static final String NEARBY_FAST_PAIR_SETTINGS_DEVICES_COMPONENT = + "nearby_fast_pair_settings_devices_component"; /** - * Whether or not the automatic storage manager is enabled and should run on the device. - * + * Current provider of the component for requesting ambient context consent. + * Default value in @string/config_defaultAmbientContextConsentComponent. + * No VALIDATOR as this setting will not be backed up. * @hide */ - @Readable - public static final String AUTOMATIC_STORAGE_MANAGER_ENABLED = - "automatic_storage_manager_enabled"; + public static final String AMBIENT_CONTEXT_CONSENT_COMPONENT = + "ambient_context_consent_component"; /** - * How many days of information for the automatic storage manager to retain on the device. - * + * Current provider of the intent extra key for the caller's package name while + * requesting ambient context consent. + * No VALIDATOR as this setting will not be backed up. * @hide */ - @Readable - public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN = - "automatic_storage_manager_days_to_retain"; + public static final String AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY = + "ambient_context_package_name_key"; /** - * Default number of days of information for the automatic storage manager to retain. - * + * Current provider of the intent extra key for the event code int array while + * requesting ambient context consent. + * Default value in @string/config_ambientContextEventArrayExtraKey. + * No VALIDATOR as this setting will not be backed up. * @hide */ - public static final int AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT = 90; + public static final String AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY = + "ambient_context_event_array_key"; /** - * How many bytes the automatic storage manager has cleared out. - * + * Controls whether aware is enabled. * @hide */ @Readable - public static final String AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED = - "automatic_storage_manager_bytes_cleared"; + public static final String AWARE_ENABLED = "aware_enabled"; /** - * Last run time for the automatic storage manager. - * + * Controls whether aware_lock is enabled. * @hide */ @Readable - public static final String AUTOMATIC_STORAGE_MANAGER_LAST_RUN = - "automatic_storage_manager_last_run"; + public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled"; + /** - * If the automatic storage manager has been disabled by policy. Note that this doesn't - * mean that the automatic storage manager is prevented from being re-enabled -- this only - * means that it was turned off by policy at least once. - * + * Controls whether tap gesture is enabled. * @hide */ @Readable - public static final String AUTOMATIC_STORAGE_MANAGER_TURNED_OFF_BY_POLICY = - "automatic_storage_manager_turned_off_by_policy"; + public static final String TAP_GESTURE = "tap_gesture"; /** - * Whether SystemUI navigation keys is enabled. + * Controls whether the people strip is enabled. * @hide */ @Readable - public static final String SYSTEM_NAVIGATION_KEYS_ENABLED = - "system_navigation_keys_enabled"; + public static final String PEOPLE_STRIP = "people_strip"; /** - * Holds comma separated list of ordering of QS tiles. - * + * Whether or not to enable media resumption + * When enabled, media controls in quick settings will populate on boot and persist if + * resumable via a MediaBrowserService. + * @see Settings.Global#SHOW_MEDIA_ON_QUICK_SETTINGS * @hide */ - @Readable(maxTargetSdk = VERSION_CODES.TIRAMISU) - public static final String QS_TILES = "sysui_qs_tiles"; + @Readable + public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption"; /** - * Whether this user has enabled Quick controls. - * - * 0 indicates disabled and 1 indicates enabled. A non existent value should be treated as - * enabled. - * - * @deprecated Controls are migrated to Quick Settings, rendering this unnecessary and will - * be removed in a future release. + * Whether to enable media controls on lock screen. + * When enabled, media controls will appear on lock screen. * @hide */ - @Readable - @Deprecated - public static final String CONTROLS_ENABLED = "controls_enabled"; + public static final String MEDIA_CONTROLS_LOCK_SCREEN = "media_controls_lock_screen"; /** - * Whether power menu content (cards, passes, controls) will be shown when device is locked. - * - * 0 indicates hide and 1 indicates show. A non existent value will be treated as hide. + * Whether to enable camera extensions software fallback. * @hide */ - @TestApi @Readable - public static final String POWER_MENU_LOCKED_SHOW_CONTENT = - "power_menu_locked_show_content"; + public static final String CAMERA_EXTENSIONS_FALLBACK = "camera_extensions_fallback"; /** - * Whether home controls should be accessible from the lockscreen + * Controls magnification mode when magnification is enabled via a system-wide triple tap + * gesture or the accessibility shortcut. * + * @see #ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN + * @see #ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW * @hide */ - public static final String LOCKSCREEN_SHOW_CONTROLS = "lockscreen_show_controls"; + @TestApi + @Readable + public static final String ACCESSIBILITY_MAGNIFICATION_MODE = + "accessibility_magnification_mode"; /** - * Whether trivial home controls can be used without authentication - * + * Magnification mode value that is a default value for the magnification logging feature. * @hide */ - public static final String LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS = - "lockscreen_allow_trivial_controls"; + public static final int ACCESSIBILITY_MAGNIFICATION_MODE_NONE = 0x0; /** - * Whether wallet should be accessible from the lockscreen - * + * Magnification mode value that magnifies whole display. * @hide */ - public static final String LOCKSCREEN_SHOW_WALLET = "lockscreen_show_wallet"; + @TestApi + public static final int ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN = 0x1; /** - * Whether to use the lockscreen double-line clock - * + * Magnification mode value that magnifies magnify particular region in a window * @hide */ - public static final String LOCKSCREEN_USE_DOUBLE_LINE_CLOCK = - "lockscreen_use_double_line_clock"; + @TestApi + public static final int ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW = 0x2; /** - * Whether to show the vibrate icon in the Status Bar (default off) - * + * Magnification mode value that is capable of magnifying whole display and particular + * region in a window. * @hide */ - public static final String STATUS_BAR_SHOW_VIBRATE_ICON = "status_bar_show_vibrate_icon"; + @TestApi + public static final int ACCESSIBILITY_MAGNIFICATION_MODE_ALL = 0x3; /** - * Specifies whether the web action API is enabled. + * Whether the magnification always on feature is enabled. If true, the magnifier will not + * deactivate on Activity transitions; it will only zoom out to 100%. * * @hide */ - @SystemApi - @Readable - public static final String INSTANT_APPS_ENABLED = "instant_apps_enabled"; + public static final String ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED = + "accessibility_magnification_always_on_enabled"; /** - * Whether qr code scanner should be accessible from the lockscreen + * Controls how the magnification follows the cursor. * * @hide */ - public static final String LOCK_SCREEN_SHOW_QR_CODE_SCANNER = - "lock_screen_show_qr_code_scanner"; + public static final String ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE = + "accessibility_magnification_cursor_following_mode"; /** - * Whether or not to enable qr code code scanner setting to enable/disable lockscreen - * entry point. Any value apart from null means setting needs to be enabled + * Magnification cursor following mode value for the continuous mode. * * @hide */ - public static final String SHOW_QR_CODE_SCANNER_SETTING = - "show_qr_code_scanner_setting"; + public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS = 0; /** - * Has this pairable device been paired or upgraded from a previously paired system. + * Magnification cursor following mode value for the center mode. + * * @hide */ - @Readable - public static final String DEVICE_PAIRED = "device_paired"; + public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER = 1; /** - * Specifies additional package name for broadcasting the CMAS messages. + * Magnification cursor following mode value for the edge mode. + * * @hide */ - @Readable - public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg"; + public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE = 2; /** - * Whether the launcher should show any notification badges. - * The value is boolean (1 or 0). + * Different cursor following settings that can be used as values with + * {@link #ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE}. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi - @Readable - public static final String NOTIFICATION_BADGING = "notification_badging"; - - /** - * When enabled the system will maintain a rolling history of received notifications. When - * disabled the history will be disabled and deleted. - * - * The value 1 - enable, 0 - disable + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_" }, + value = { + ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS, + ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER, + ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE}) + public @interface AccessibilityMagnificationCursorFollowingMode {} + + /** + * Whether the following typing focus feature for magnification is enabled. * @hide */ - @Readable - public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled"; + public static final String ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED = + "accessibility_magnification_follow_typing_enabled"; /** - * When enabled conversations marked as favorites will be set to bubble. - * - * The value 1 - enable, 0 - disable + * Whether the following keyboard focus feature for magnification is enabled. * @hide */ - @Readable - public static final String BUBBLE_IMPORTANT_CONVERSATIONS - = "bubble_important_conversations"; + public static final String ACCESSIBILITY_MAGNIFICATION_FOLLOW_KEYBOARD_ENABLED = + "accessibility_magnification_follow_keyboard_enabled"; /** - * When enabled, notifications able to bubble will display an affordance allowing the user - * to bubble them. - * The value is boolean (1 to enable or 0 to disable). - * + * Whether the magnification joystick controller feature is enabled. * @hide */ - @TestApi - @SuppressLint("NoSettingsProvider") - @Readable - public static final String NOTIFICATION_BUBBLES = "notification_bubbles"; + public static final String ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED = + "accessibility_magnification_joystick_enabled"; /** - * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right - * swipe). + * Setting that specifies whether the display magnification is enabled via a system-wide + * two fingers triple tap gesture. * * @hide */ - @Readable - public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl"; + public static final String ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED = + "accessibility_magnification_two_finger_triple_tap_enabled"; /** - * Comma separated list of QS tiles that have been auto-added already. + * Whether to always expand notification bundles in the notification shade. + * 1 = expand, 0 = collapse. * @hide */ - @Readable - public static final String QS_AUTO_ADDED_TILES = "qs_auto_tiles"; + public static final String NOTIFICATION_BUNDLES_ALWAYS_EXPAND = + "notification_bundles_always_expand"; /** - * The duration of timeout, in milliseconds, to switch from a non-Dock User to the - * Dock User when the device is docked. + * Whether the magnify navigation bar and keyboard feature is enabled. + * * @hide */ - public static final String TIMEOUT_TO_DOCK_USER = "timeout_to_dock_user"; + public static final String ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME = + "accessibility_magnification_magnify_nav_and_ime"; /** - * Backup manager behavioral parameters. - * This is encoded as a key=value list, separated by commas. Ex: - * - * "key_value_backup_interval_milliseconds=14400000,key_value_backup_require_charging=true" - * - * The following keys are supported: - * - *

-         * key_value_backup_interval_milliseconds  (long)
-         * key_value_backup_fuzz_milliseconds      (long)
-         * key_value_backup_require_charging       (boolean)
-         * key_value_backup_required_network_type  (int)
-         * full_backup_interval_milliseconds       (long)
-         * full_backup_require_charging            (boolean)
-         * full_backup_required_network_type       (int)
-         * backup_finished_notification_receivers  (String[])
-         * 
+ * For pinch to zoom anywhere feature. * - * backup_finished_notification_receivers uses ":" as delimiter for values. + * If true, you should be able to pinch to magnify the window anywhere. * - *

- * Type: string * @hide */ - @Readable - public static final String BACKUP_MANAGER_CONSTANTS = "backup_manager_constants"; - + public static final String ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED = + "accessibility_pinch_to_zoom_anywhere_enabled"; /** - * Local transport parameters so we can configure it for tests. - * This is encoded as a key=value list, separated by commas. - * - * The following keys are supported: + * For magnification feature where panning can be controlled with a single finger. * - *

-         * fake_encryption_flag  (boolean)
-         * 
+ * If true, you can pan using a single finger gesture. * - *

- * Type: string * @hide */ - @Readable - public static final String BACKUP_LOCAL_TRANSPORT_PARAMETERS = - "backup_local_transport_parameters"; + public static final String ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED = + "accessibility_single_finger_panning_enabled"; /** - * Flag to set if the system should predictively attempt to re-enable Bluetooth while - * the user is driving. + * Controls magnification capability. Accessibility magnification is capable of at least one + * of the magnification modes. + * + * @see #ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN + * @see #ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW + * @see #ACCESSIBILITY_MAGNIFICATION_MODE_ALL * @hide */ + @TestApi @Readable - public static final String BLUETOOTH_ON_WHILE_DRIVING = "bluetooth_on_while_driving"; + public static final String ACCESSIBILITY_MAGNIFICATION_CAPABILITY = + "accessibility_magnification_capability"; /** - * Volume dialog timeout in ms. + * Whether to show the window magnification prompt dialog when the user uses full-screen + * magnification first time after database is upgraded. + * * @hide */ - public static final String VOLUME_DIALOG_DISMISS_TIMEOUT = "volume_dialog_dismiss_timeout"; + public static final String ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT = + "accessibility_show_window_magnification_prompt"; /** - * What behavior should be invoked when the volume hush gesture is triggered - * One of VOLUME_HUSH_OFF, VOLUME_HUSH_VIBRATE, VOLUME_HUSH_MUTE. + * Controls the accessibility button mode. System will force-set the value to {@link + * #ACCESSIBILITY_BUTTON_MODE_GESTURE} if {@link #NAVIGATION_MODE} is button; force-set the + * value to {@link ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} if {@link #NAVIGATION_MODE} is + * gestural; otherwise, remain the option. + *

    + *
  • 0 = button in navigation bar
  • + *
  • 1 = button floating on the display
  • + *
  • 2 = button using gesture to trigger
  • + *
* + * @see #ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR + * @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU + * @see #ACCESSIBILITY_BUTTON_MODE_GESTURE * @hide */ - @SystemApi - @Readable - public static final String VOLUME_HUSH_GESTURE = "volume_hush_gesture"; - - /** @hide */ - @SystemApi - public static final int VOLUME_HUSH_OFF = 0; - /** @hide */ - @SystemApi - public static final int VOLUME_HUSH_VIBRATE = 1; - /** @hide */ - @SystemApi - public static final int VOLUME_HUSH_MUTE = 2; + public static final String ACCESSIBILITY_BUTTON_MODE = + "accessibility_button_mode"; /** - * The number of times (integer) the user has manually enabled battery saver. + * Accessibility button mode value that specifying the accessibility service or feature to + * be toggled via the button in the navigation bar. + * * @hide */ - @Readable - public static final String LOW_POWER_MANUAL_ACTIVATION_COUNT = - "low_power_manual_activation_count"; + public static final int ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR = 0x0; /** - * Whether the "first time battery saver warning" dialog needs to be shown (0: default) - * or not (1). + * Accessibility button mode value that specifying the accessibility service or feature to + * be toggled via the button floating on the display. * * @hide */ - @Readable - public static final String LOW_POWER_WARNING_ACKNOWLEDGED = - "low_power_warning_acknowledged"; + public static final int ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU = 0x1; /** - * Whether the "first time extra battery saver warning" dialog needs to be shown - * (0: default) or not (1). + * Accessibility button mode value that specifying the accessibility service or feature to + * be toggled via the gesture. * * @hide */ - public static final String EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED = - "extra_low_power_warning_acknowledged"; + public static final int ACCESSIBILITY_BUTTON_MODE_GESTURE = 0x2; /** - * Whether the emergency thermal alert would be disabled - * (0: default) or not (1). + * The size of the accessibility floating menu. + *
    + *
  • 0 = small size + *
  • 1 = large size + *
* * @hide */ - public static final String EMERGENCY_THERMAL_ALERT_DISABLED = - "emergency_thermal_alert_disabled"; + public static final String ACCESSIBILITY_FLOATING_MENU_SIZE = + "accessibility_floating_menu_size"; /** - * 0 (default) Auto battery saver suggestion has not been suppressed. 1) it has been - * suppressed. + * The icon type of the accessibility floating menu. + *
    + *
  • 0 = full circle type + *
  • 1 = half circle type + *
+ * * @hide */ - @Readable - public static final String SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION = - "suppress_auto_battery_saver_suggestion"; + public static final String ACCESSIBILITY_FLOATING_MENU_ICON_TYPE = + "accessibility_floating_menu_icon_type"; /** - * List of packages, which data need to be unconditionally cleared before full restore. - * Type: string + * Whether the fade effect for the accessibility floating menu is enabled. + * * @hide */ - @Readable - public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE = - "packages_to_clear_data_before_full_restore"; + public static final String ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED = + "accessibility_floating_menu_fade_enabled"; /** - * How often to check for location access. - * @hide - * - * @deprecated This has been moved to DeviceConfig property - * {@link LocationAccessCheck#PROPERTY_LOCATION_ACCESS_PERIODIC_INTERVAL_MILLIS} in a T - * module update + * The opacity value for the accessibility floating menu fade out effect, from 0.0 + * (transparent) to 1.0 (opaque). * - * Before Android T set this property to control the interval for the check - * On Android T set this and the DeviceConfig property - * After Android T set the DeviceConfig property + * @hide */ - @SystemApi - @Deprecated - @Readable - public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = - "location_access_check_interval_millis"; + public static final String ACCESSIBILITY_FLOATING_MENU_OPACITY = + "accessibility_floating_menu_opacity"; /** - * Delay between granting location access and checking it. + * Prompts the user to the Accessibility button is replaced with the floating menu. + *
    + *
  • 0 = disabled
  • + *
  • 1 = enabled
  • + *
+ * * @hide + */ + public static final String ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT = + "accessibility_floating_menu_migration_tooltip_prompt"; + + /** + * For the force dark theme feature which inverts any apps that don't already support dark + * theme. * - * @deprecated This has been moved to DeviceConfig property - * {@link LocationAccessCheck#PROPERTY_LOCATION_ACCESS_CHECK_DELAY_MILLIS} in a T module - * update + * If true, it will automatically invert any app that is mainly light. * - * Before Android T set this property to control the delay for the check - * On Android T set this and the DeviceConfig property - * After Android T set the DeviceConfig property + * This is related to the force dark override setting, however it will always force the apps + * colors and will ignore any developer hints or opt-out APIs. + * + * @hide */ - @SystemApi - @Deprecated + @TestApi @Readable - public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = - "location_access_check_delay_millis"; + @FlaggedApi(android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR) + @SuppressLint("NoSettingsProvider") + public static final String ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED = + "accessibility_force_invert_color_enabled"; /** - * @deprecated This setting does not have any effect anymore + * Whether to enable mouse keys for Physical Keyboard accessibility. + * + * If set to true, key presses (of the mouse keys) on + * physical keyboard will control mouse pointer on the display. + * * @hide */ - @SystemApi - @Deprecated @Readable - public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = - "location_permissions_upgrade_to_q_mode"; + public static final String ACCESSIBILITY_MOUSE_KEYS_ENABLED = + "accessibility_mouse_keys_enabled"; /** - * Whether or not the system Auto Revoke feature is disabled. + * The current float acceleration value for mouse keys movement. + * * @hide */ - @SystemApi - @Readable - public static final String AUTO_REVOKE_DISABLED = "auto_revoke_disabled"; + public static final String ACCESSIBILITY_MOUSE_KEYS_ACCELERATION = + "accessibility_mouse_keys_acceleration"; /** - * Map of android.theme.customization.* categories to the enabled overlay package for that - * category, formatted as a serialized {@link org.json.JSONObject}. If there is no - * corresponding package included for a category, then all overlay packages in that - * category must be disabled. - * - * A few category keys have special meaning and are used for Material You theming. - * - * A {@code FabricatedOverlay} containing Material You tonal palettes will be generated - * in case {@code android.theme.customization.system_palette} contains a - * {@link android.annotation.ColorInt}. - * - * The strategy used for generating the tonal palettes can be defined with the - * {@code android.theme.customization.theme_style} key, with one of the following options: - *
    - *
  • {@code TONAL_SPOT} is a mid vibrancy palette that uses an accent 3 analogous to - * accent 1.
  • - *
  • {@code VIBRANT} is a high vibrancy palette that harmoniously blends subtle shifts - * between colors.
  • - *
  • {@code EXPRESSIVE} is a high vibrancy palette that pairs unexpected and unique - * accents colors together.
  • - *
  • {@code SPRITZ} is a low vibrancy palette that creates a soft wash between - * colors.
  • - *
  • {@code RAINBOW} uses both chromatic accents and neutral surfaces to create a more - * subtle color experience for users.
  • - *
  • {@code FRUIT_SALAD} experiments with the concept of "two tone colors" to give - * users more expression.
  • - *
+ * The max speed as a factor of the minimum speed for mouse keys movement. * - * Example of valid fabricated theme specification: - *
-         * {
-         *     "android.theme.customization.system_palette":"B1611C",
-         *     "android.theme.customization.theme_style":"EXPRESSIVE"
-         * }
-         * 
* @hide */ - @SystemApi - @Readable - public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = - "theme_customization_overlay_packages"; + public static final String ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED = + "accessibility_mouse_keys_max_speed"; /** - * Indicates whether the nav bar is forced to always be visible, even in immersive mode. - *

Type: int (0 for false, 1 for true) + * Whether the primary keys are selected to control the mouse keys. * * @hide */ - public static final String NAV_BAR_FORCE_VISIBLE = "nav_bar_force_visible"; + public static final String ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS = + "accessibility_mouse_keys_use_primary_keys"; /** - * Indicates whether the device is in kids nav mode. - *

Type: int (0 for false, 1 for true) + * Whether the Adaptive connectivity option is enabled. * * @hide */ - public static final String NAV_BAR_KIDS_MODE = "nav_bar_kids_mode"; + public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled"; /** - * This defines the order in which the 3-button navigation bar's buttons are displayed. - * 0 = left-to-right (back, home, recent) - * 1 = right-to-left (recent, home, back) + * Whether the Adaptive wifi scorer switch is enabled. + * * @hide */ - public static final String NAVIGATIONBAR_KEY_ORDER = "navigationbar_key_order"; + public static final String ADAPTIVE_CONNECTIVITY_WIFI_ENABLED = + "adaptive_connectivity_wifi_enabled"; /** - * Navigation bar mode. - * 0 = 3 button - * 1 = 2 button - * 2 = fully gestural + * Whether the Adaptive 5G PM switch is enabled. + * * @hide */ - @Readable - public static final String NAVIGATION_MODE = - "navigation_mode"; + public static final String ADAPTIVE_CONNECTIVITY_MOBILE_NETWORK_ENABLED = + "adaptive_connectivity_mobile_network_enabled"; /** - * The value is from another(source) device's {@link #NAVIGATION_MODE} during restore. - * It's supposed to be written only by - * {@link com.android.providers.settings.SettingsHelper}. - * This setting should not be added into backup array. - *

Value: -1 = Can't get value from restore(default), - * 0 = 3 button, - * 1 = 2 button, - * 2 = fully gestural. + * Controls the 'Sunlight boost' toggle in wearable devices (high brightness mode). + * + * Valid values for this key are: '0' (disabled) or '1' (enabled). + * * @hide */ - public static final String NAVIGATION_MODE_RESTORE = "navigation_mode_restore"; + public static final String HBM_SETTING_KEY = + "com.android.server.display.HBM_SETTING_KEY"; /** - * Scale factor for the back gesture inset size on the left side of the screen. + * Whether to show privacy indicator for location * @hide */ - @Readable - public static final String BACK_GESTURE_INSET_SCALE_LEFT = - "back_gesture_inset_scale_left"; + public static final String ENABLE_LOCATION_PRIVACY_INDICATOR = "enable_location_privacy_indicator"; /** - * Scale factor for the back gesture inset size on the right side of the screen. + * Whether to show privacy indicator for camera * @hide */ - @Readable - public static final String BACK_GESTURE_INSET_SCALE_RIGHT = - "back_gesture_inset_scale_right"; + public static final String ENABLE_CAMERA_PRIVACY_INDICATOR = "enable_camera_privacy_indicator"; /** - * Current provider of proximity-based sharing services. - * Default value in @string/config_defaultNearbySharingComponent. - * No VALIDATOR as this setting will not be backed up. + * Whether to show privacy indicator for media projection * @hide */ - @Readable - public static final String NEARBY_SHARING_COMPONENT = "nearby_sharing_component"; + public static final String ENABLE_PROJECTION_PRIVACY_INDICATOR = "enable_projection_privacy_indicator"; /** - * Nearby Sharing Slice URI for the SliceProvider to - * read Nearby Sharing scan results and then draw the UI. + * Whether to allow swipe down on lockscreen to view Quick Panel * @hide */ - public static final String NEARBY_SHARING_SLICE_URI = "nearby_sharing_slice_uri"; + public static final String ENABLE_LOCKSCREEN_QUICK_SETTINGS = "enable_lockscreen_quick_settings"; /** - * Current provider of Fast Pair saved devices page. - * Default value in @string/config_defaultNearbyFastPairSettingsDevicesComponent. - * No VALIDATOR as this setting will not be backed up. + * Pulse lockscreen music visualizer * @hide */ - public static final String NEARBY_FAST_PAIR_SETTINGS_DEVICES_COMPONENT = - "nearby_fast_pair_settings_devices_component"; + public static final String LOCKSCREEN_PULSE_ENABLED = "lockscreen_pulse_enabled"; /** - * Current provider of the component for requesting ambient context consent. - * Default value in @string/config_defaultAmbientContextConsentComponent. - * No VALIDATOR as this setting will not be backed up. + * Pulse lockscreen music visualizer on ambient display * @hide */ - public static final String AMBIENT_CONTEXT_CONSENT_COMPONENT = - "ambient_context_consent_component"; + public static final String AMBIENT_PULSE_ENABLED = "ambient_pulse_enabled"; /** - * Current provider of the intent extra key for the caller's package name while - * requesting ambient context consent. - * No VALIDATOR as this setting will not be backed up. * @hide */ - public static final String AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY = - "ambient_context_package_name_key"; + public static final String PULSE_BAR_COUNT = "pulse_bar_count"; /** - * Current provider of the intent extra key for the event code int array while - * requesting ambient context consent. - * Default value in @string/config_ambientContextEventArrayExtraKey. - * No VALIDATOR as this setting will not be backed up. * @hide */ - public static final String AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY = - "ambient_context_event_array_key"; + public static final String PULSE_ROUNDED_BARS = "pulse_rounded_bars"; /** - * Controls whether aware is enabled. * @hide */ - @Readable - public static final String AWARE_ENABLED = "aware_enabled"; + public static final String PULSE_COLOR = "pulse_color"; /** - * Controls whether aware_lock is enabled. * @hide */ - @Readable - public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled"; + public static final String PULSE_RENDERER = "pulse_renderer"; /** - * Controls whether tap gesture is enabled. * @hide */ - @Readable - public static final String TAP_GESTURE = "tap_gesture"; + public static final String PULSE_SHOW_ON_AMBIENT = "pulse_show_on_ambient"; /** - * Controls whether the people strip is enabled. * @hide */ - @Readable - public static final String PEOPLE_STRIP = "people_strip"; + public static final String PULSE_HEIGHT_MULTIPLIER = "pulse_height_multiplier"; /** - * Whether or not to enable media resumption - * When enabled, media controls in quick settings will populate on boot and persist if - * resumable via a MediaBrowserService. - * @see Settings.Global#SHOW_MEDIA_ON_QUICK_SETTINGS * @hide */ - @Readable - public static final String MEDIA_CONTROLS_RESUME = "qs_media_resumption"; - + public static final String PULSE_CUSTOM_COLOR = "pulse_custom_color"; + /** - * Whether to enable media controls on lock screen. - * When enabled, media controls will appear on lock screen. * @hide */ - public static final String MEDIA_CONTROLS_LOCK_SCREEN = "media_controls_lock_screen"; + public static final String PULSE_BASS_HAPTICS = "pulse_bass_haptics"; /** - * Whether to enable camera extensions software fallback. + * Whether to show or hide the arrow for back gesture * @hide */ - @Readable - public static final String CAMERA_EXTENSIONS_FALLBACK = "camera_extensions_fallback"; + public static final String BACK_GESTURE_ARROW = "back_gesture_arrow"; /** - * Controls magnification mode when magnification is enabled via a system-wide triple tap - * gesture or the accessibility shortcut. - * - * @see #ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN - * @see #ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW + * Whether or not to vibrate when back gesture is used * @hide */ - @TestApi - @Readable - public static final String ACCESSIBILITY_MAGNIFICATION_MODE = - "accessibility_magnification_mode"; + public static final String BACK_GESTURE_HAPTIC = "back_gesture_haptic"; /** - * Magnification mode value that is a default value for the magnification logging feature. + * Which navigation bar layout to use + * 0 = Normal (Default) + * 1 = Compact + * 2 = Left-leaning + * 3 = Right-leaning * @hide */ - public static final int ACCESSIBILITY_MAGNIFICATION_MODE_NONE = 0x0; + public static final String NAVBAR_LAYOUT_MODE = "navbar_layout_mode"; /** - * Magnification mode value that magnifies whole display. + * Show navigation space below IME * @hide */ - @TestApi - public static final int ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN = 0x1; + public static final String NAVBAR_IME_SPACE = "navbar_ime_space"; /** - * Magnification mode value that magnifies magnify particular region in a window + * Per-apps device spoofing * @hide */ - @TestApi - public static final int ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW = 0x2; + @Readable + public static final String PER_APPS_DEVICE_SPOOF = "per_apps_device_spoof"; /** - * Magnification mode value that is capable of magnifying whole display and particular - * region in a window. + * Custom device spoof profiles for per-app spoofing * @hide */ - @TestApi - public static final int ACCESSIBILITY_MAGNIFICATION_MODE_ALL = 0x3; + @Readable + public static final String CUSTOM_SPOOF_PROFILES = "custom_spoof_profiles"; + + /** + * @hide + */ + @Readable + public static final String PER_APPS_DEVICE_SPOOF_ENABLED = "per_apps_device_spoof_enabled"; + + /** + * @hide + */ + @Readable + public static final String PER_APPS_DEVICE_SPOOF_CACHE = "per_apps_device_spoof_cache"; /** - * Whether the magnification always on feature is enabled. If true, the magnifier will not - * deactivate on Activity transitions; it will only zoom out to 100%. - * + * Whether to use system accent color for lock screen clock text * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED = - "accessibility_magnification_always_on_enabled"; + public static final String CLOCK_TEXT_ACCENT_COLOR = "clock_text_accent_color"; /** - * Controls how the magnification follows the cursor. - * + * Lock screen clock text opacity (0-100) * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE = - "accessibility_magnification_cursor_following_mode"; + public static final String CLOCK_TEXT_OPACITY = "clock_text_opacity"; /** - * Magnification cursor following mode value for the continuous mode. - * + * Whether to show an overlay in the bottom corner of the screen on copying stuff + * into the clipboard. * @hide */ - public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS = 0; + public static final String SHOW_CLIPBOARD_OVERLAY = "show_clipboard_overlay"; /** - * Magnification cursor following mode value for the center mode. - * + * Whether to enable DOZE only when charging * @hide */ - public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER = 1; + public static final String DOZE_ON_CHARGE = "doze_on_charge"; /** - * Magnification cursor following mode value for the edge mode. - * + * Whether to pulse ambient on new music tracks * @hide */ - public static final int ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE = 2; + public static final String PULSE_ON_NEW_TRACKS = "pulse_on_new_tracks"; /** - * Different cursor following settings that can be used as values with - * {@link #ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE}. + * Whether to show media squiggle animation * @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_" }, - value = { - ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CONTINUOUS, - ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_CENTER, - ACCESSIBILITY_MAGNIFICATION_CURSOR_FOLLOWING_MODE_EDGE}) - public @interface AccessibilityMagnificationCursorFollowingMode {} + public static final String MEDIA_SQUIGGLE_ANIMATION = "media_squiggle_animation"; /** - * Whether the following typing focus feature for magnification is enabled. + * Control whether the process CPU info meter should be shown. * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED = - "accessibility_magnification_follow_typing_enabled"; + public static final String SHOW_CPU_OVERLAY = "show_cpu_overlay"; /** - * Whether the following keyboard focus feature for magnification is enabled. + * Control whether the process FPS info meter should be shown. * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_FOLLOW_KEYBOARD_ENABLED = - "accessibility_magnification_follow_keyboard_enabled"; + public static final String SHOW_FPS_OVERLAY = "show_fps_overlay"; /** - * Whether the magnification joystick controller feature is enabled. + * Whether to enable clipboard auto clear * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED = - "accessibility_magnification_joystick_enabled"; + public static final String CLIPBOARD_AUTO_CLEAR_ENABLED = "clipboard_auto_clear_enabled"; /** - * Setting that specifies whether the display magnification is enabled via a system-wide - * two fingers triple tap gesture. - * + * Idle Manager * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED = - "accessibility_magnification_two_finger_triple_tap_enabled"; + public static final String IDLE_MANAGER = "idle_manager"; /** - * Whether to always expand notification bundles in the notification shade. - * 1 = expand, 0 = collapse. * @hide */ - public static final String NOTIFICATION_BUNDLES_ALWAYS_EXPAND = - "notification_bundles_always_expand"; + public static final String IDLE_MANAGER_APPS = "idle_manager_apps"; /** - * Whether the magnify navigation bar and keyboard feature is enabled. - * * @hide */ - public static final String ACCESSIBILITY_MAGNIFICATION_MAGNIFY_NAV_AND_IME = - "accessibility_magnification_magnify_nav_and_ime"; + public static final String IDLE_MANAGER_TIMEOUT = "idle_manager_timeout"; /** - * For pinch to zoom anywhere feature. - * - * If true, you should be able to pinch to magnify the window anywhere. - * * @hide */ - public static final String ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED = - "accessibility_pinch_to_zoom_anywhere_enabled"; + public static final String IDLE_MANAGER_KILL_STATS = "idle_manager_kill_stats"; /** - * For magnification feature where panning can be controlled with a single finger. - * - * If true, you can pan using a single finger gesture. - * + * Lockscreen custom clock face * @hide */ - public static final String ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED = - "accessibility_single_finger_panning_enabled"; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_STYLE = "lock_screen_custom_clock_style"; /** - * Controls magnification capability. Accessibility magnification is capable of at least one - * of the magnification modes. - * - * @see #ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN - * @see #ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW - * @see #ACCESSIBILITY_MAGNIFICATION_MODE_ALL + * Whether to use default, system accent or custom color for lock screen clock text * @hide */ - @TestApi - @Readable - public static final String ACCESSIBILITY_MAGNIFICATION_CAPABILITY = - "accessibility_magnification_capability"; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_COLOR_MODE = "lock_screen_custom_clock_color_mode"; /** - * Whether to show the window magnification prompt dialog when the user uses full-screen - * magnification first time after database is upgraded. - * + * Custom color for lock screen clock text * @hide */ - public static final String ACCESSIBILITY_SHOW_WINDOW_MAGNIFICATION_PROMPT = - "accessibility_show_window_magnification_prompt"; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_CUSTOM_COLOR = "lock_screen_custom_clock_custom_color"; /** - * Controls the accessibility button mode. System will force-set the value to {@link - * #ACCESSIBILITY_BUTTON_MODE_GESTURE} if {@link #NAVIGATION_MODE} is button; force-set the - * value to {@link ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} if {@link #NAVIGATION_MODE} is - * gestural; otherwise, remain the option. - *

    - *
  • 0 = button in navigation bar
  • - *
  • 1 = button floating on the display
  • - *
  • 2 = button using gesture to trigger
  • - *
- * - * @see #ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR - * @see #ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU - * @see #ACCESSIBILITY_BUTTON_MODE_GESTURE + * Lock screen clock text opacity (0-100) * @hide */ - public static final String ACCESSIBILITY_BUTTON_MODE = - "accessibility_button_mode"; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_OPACITY = "lock_screen_custom_clock_opacity"; /** - * Accessibility button mode value that specifying the accessibility service or feature to - * be toggled via the button in the navigation bar. - * + * Adjust top margin for custom clock * @hide */ - public static final int ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR = 0x0; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_MARGIN_TOP = "lock_screen_custom_clock_margin_top"; /** - * Accessibility button mode value that specifying the accessibility service or feature to - * be toggled via the button floating on the display. - * + * Custom clock size * @hide */ - public static final int ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU = 0x1; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_SIZE = "lock_screen_custom_clock_size_scale"; /** - * Accessibility button mode value that specifying the accessibility service or feature to - * be toggled via the gesture. - * + * Custom clock animation * @hide */ - public static final int ACCESSIBILITY_BUTTON_MODE_GESTURE = 0x2; + public static final String LOCK_SCREEN_CUSTOM_CLOCK_AOD_ANIM = "lock_screen_custom_clock_aod_anim"; /** - * The size of the accessibility floating menu. - *
    - *
  • 0 = small size - *
  • 1 = large size - *
- * + * Timeout length for clipboard auto clear * @hide */ - public static final String ACCESSIBILITY_FLOATING_MENU_SIZE = - "accessibility_floating_menu_size"; + public static final String CLIPBOARD_AUTO_CLEAR_TIMEOUT = "clipboard_auto_clear_timeout"; /** - * The icon type of the accessibility floating menu. - *
    - *
  • 0 = full circle type - *
  • 1 = half circle type - *
+ * Whether to turn off Private DNS {@link #PRIVATE_DNS_MODE} + * when a VPN is connected + *

+ * Set to 1 for true and 0 for false. Default 0. * * @hide */ - public static final String ACCESSIBILITY_FLOATING_MENU_ICON_TYPE = - "accessibility_floating_menu_icon_type"; + public static final String VPN_ENFORCE_DNS = "vpn_enforce_dns"; /** - * Whether the fade effect for the accessibility floating menu is enabled. + * A setting used to store the last mode of {@link #PRIVATE_DNS_MODE} + * used for {@link #VPN_ENFORCE_DNS} + * Not for backup! * * @hide */ - public static final String ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED = - "accessibility_floating_menu_fade_enabled"; + public static final String VPN_ENFORCE_DNS_STORE = "vpn_enforce_dns_store"; /** - * The opacity value for the accessibility floating menu fade out effect, from 0.0 - * (transparent) to 1.0 (opaque). - * + * Whether to show ambient instead of waking for the tap gesture * @hide */ - public static final String ACCESSIBILITY_FLOATING_MENU_OPACITY = - "accessibility_floating_menu_opacity"; + public static final String DOZE_TAP_GESTURE_AMBIENT = "doze_tap_gesture_ambient"; /** - * Prompts the user to the Accessibility button is replaced with the floating menu. - *

    - *
  • 0 = disabled
  • - *
  • 1 = enabled
  • - *
- * + * Whether to show ambient instead of waking for the pickup gesture + * Do note quick pickup (device sensor) is already configured to do that * @hide */ - public static final String ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT = - "accessibility_floating_menu_migration_tooltip_prompt"; - + public static final String DOZE_PICK_UP_GESTURE_AMBIENT = "doze_pick_up_gesture_ambient"; + /** - * For the force dark theme feature which inverts any apps that don't already support dark - * theme. - * - * If true, it will automatically invert any app that is mainly light. - * - * This is related to the force dark override setting, however it will always force the apps - * colors and will ignore any developer hints or opt-out APIs. - * + * Translucent notifications * @hide */ - @TestApi - @Readable - @FlaggedApi(android.view.accessibility.Flags.FLAG_FORCE_INVERT_COLOR) - @SuppressLint("NoSettingsProvider") - public static final String ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED = - "accessibility_force_invert_color_enabled"; + public static final String NOTIFICATION_ROW_TRANSPARENCY = "notification_row_transparency"; /** - * Whether to enable mouse keys for Physical Keyboard accessibility. - * - * If set to true, key presses (of the mouse keys) on - * physical keyboard will control mouse pointer on the display. - * + * Translucent lockscreen notifications * @hide */ - @Readable - public static final String ACCESSIBILITY_MOUSE_KEYS_ENABLED = - "accessibility_mouse_keys_enabled"; + public static final String NOTIFICATION_ROW_TRANSPARENCY_LOCKSCREEN = "notification_row_transparency_lockscreen"; /** - * The current float acceleration value for mouse keys movement. - * + * Whether to use PixelProps spoof for google apps * @hide */ - public static final String ACCESSIBILITY_MOUSE_KEYS_ACCELERATION = - "accessibility_mouse_keys_acceleration"; + @Readable + public static final String PI_PP_SPOOF = "pi_pp_spoof"; /** - * The max speed as a factor of the minimum speed for mouse keys movement. - * + * Whether to use Tensor spoof for google apps * @hide */ - public static final String ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED = - "accessibility_mouse_keys_max_speed"; + @Readable + public static final String PI_TENSOR_SPOOF = "pi_tensor_spoof"; /** - * Whether the primary keys are selected to control the mouse keys. - * + * Whether to use PIF spoof for Play store * @hide */ - public static final String ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS = - "accessibility_mouse_keys_use_primary_keys"; + @Readable + public static final String PI_VENDING_SPOOF = "pi_vending_spoof"; /** - * Whether the Adaptive connectivity option is enabled. - * + * Whether to use spoof for photos * @hide */ - public static final String ADAPTIVE_CONNECTIVITY_ENABLED = "adaptive_connectivity_enabled"; + @Readable + public static final String PI_PHOTOS_SPOOF = "pi_photos_spoof"; /** - * Whether the Adaptive wifi scorer switch is enabled. - * + * Whether to use spoof for snapchat * @hide */ - public static final String ADAPTIVE_CONNECTIVITY_WIFI_ENABLED = - "adaptive_connectivity_wifi_enabled"; + @Readable + public static final String PI_SNAPCHAT_SPOOF = "pi_snapchat_spoof"; /** - * Whether the Adaptive 5G PM switch is enabled. - * + * Whether to enable Smart Pixels * @hide */ - public static final String ADAPTIVE_CONNECTIVITY_MOBILE_NETWORK_ENABLED = - "adaptive_connectivity_mobile_network_enabled"; + public static final String SMART_PIXEL_FILTER_ENABLED = "smart_pixel_filter_enabled"; /** - * Controls the 'Sunlight boost' toggle in wearable devices (high brightness mode). - * - * Valid values for this key are: '0' (disabled) or '1' (enabled). - * + * Smart Pixels percentage * @hide */ - public static final String HBM_SETTING_KEY = - "com.android.server.display.HBM_SETTING_KEY"; + public static final String SMART_PIXEL_FILTER_PERCENT = "smart_pixel_filter_percent"; /** * Keys we no longer back up under the current schema, but want to continue to @@ -13624,11 +15107,10 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val "hinge_angle_lidevent_enabled"; /** - * Whether lockscreen weather is enabled. - * + * Whether lockscreen smartspace is enabled. * @hide */ - public static final String LOCK_SCREEN_WEATHER_ENABLED = "lockscreen_weather_enabled"; + public static final String LOCKSCREEN_SMARTSPACE_ENABLED = "lockscreen_smartspace_enabled"; /** * Whether the feature that the device will fire a haptic when users scroll and hit @@ -13733,6 +15215,92 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val public static final String OTP_NOTIFICATION_REDACTION_LOCK_TIME = "otp_redaction_lock_time"; + /** + * Whether to vibrate for the dt2w gesture + * @hide + */ + public static final String DOZE_DOUBLE_TAP_GESTURE_VIBRATE = "doze_double_tap_gesture_vibrate"; + + /** + * Whether to vibrate for the tap gesture + * @hide + */ + public static final String DOZE_TAP_GESTURE_VIBRATE = "doze_tap_gesture_vibrate"; + + /** + * Whether to vibrate for the pickup gesture + * @hide + */ + public static final String DOZE_PICK_UP_GESTURE_VIBRATE = "doze_pick_up_gesture_vibrate"; + + /** + * Boolean value whether activate keyguard affordance shortcuts on short press + * @hide + */ + public static final String KEYGUARD_AFFORDANCE_SINGLE_TAP = "keyguard_affordance_single_tap"; + + /** + * Whether to enable Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_ENABLED = "sleep_mode_enabled"; + + /** + * Indicates whether Sleep Mode turns on automatically + * 0 = disabled (default) + * 1 = from sunset to sunrise + * 2 = custom time + * 3 = from sunset till a time + * 4 = from a time till sunrise + * @hide + */ + public static final String SLEEP_MODE_AUTO_MODE = "sleep_mode_auto_mode"; + + /** + * The custom time {@link SLEEP_MODE_ENABLED} should be on at + * Only relevant when {@link SLEEP_MODE_AUTO_MODE} is set to 2 and above + * 0 = Disabled (default) + * format: HH:mm,HH:mm (since,till) + * @hide + */ + public static final String SLEEP_MODE_AUTO_TIME = "sleep_mode_auto_time"; + + /** + * Whether to disable Wi-Fi in Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_WIFI_TOGGLE = "sleep_mode_wifi_toggle"; + + /** + * Whether to disable Bluetooth in Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_BLUETOOTH_TOGGLE = "sleep_mode_bluetooth_toggle"; + + /** + * Whether to disable Mobile data in Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_CELLULAR_TOGGLE = "sleep_mode_cellular_toggle"; + + /** + * Whether to disable Sensors in Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_SENSORS_TOGGLE = "sleep_mode_sensors_toggle"; + + /** + * Whether to reduce background activity in Sleep Mode + * @hide + */ + public static final String SLEEP_MODE_IDLE_TOGGLE = "sleep_mode_idle_toggle"; + + /** + * Ringer in Sleep Mode (0:OFF, 1:Vibrate, 2:DND, 3:Silent) + * @hide + */ + public static final String SLEEP_MODE_RINGER_MODE = "sleep_mode_ringer_mode"; + /** * These entries are considered common between the personal and the managed profile, * since the managed profile doesn't get to change them. @@ -13851,6 +15419,7 @@ public static void setLocationProviderEnabled(ContentResolver cr, * * @hide */ + @Readable public static final String CHARGE_OPTIMIZATION_MODE = "charge_optimization_mode"; /** @@ -13893,6 +15462,31 @@ public static void setLocationProviderEnabled(ContentResolver cr, */ public static final String IDENTITY_CHECK_NOTIFICATION_VIEW_DETAILS_CLICKED = "identity_check_notification_view_details_clicked"; + + /** + * @hide + */ + public static final String SPOOF_PIF_CONFIG = "spoof_pif_config"; + + /** + * @hide + */ + public static final String SPOOF_GAMEPROPS_CONFIG = "spoof_gameprops_config"; + + /** + * @hide + */ + public static final String SPOOF_TRICKYSTORE_TARGET = "spoof_trickystore_target"; + + /** + * @hide + */ + public static final String SPOOF_TRICKYSTORE_KEYBOX = "spoof_trickystore_keybox"; + + /** + * @hide + */ + public static final String SPOOF_TRICKYSTORE_PATCH = "spoof_trickystore_patch"; } /** @@ -17527,6 +19121,30 @@ public static final class Global extends NameValueTable { public static final String PREFERRED_NETWORK_MODE = "preferred_network_mode"; + /** + * Force LTE Carrier Aggregation setting per SIM slot. + * Use FORCE_LTE_CA_0 for SIM slot 0 (first SIM) + * Use FORCE_LTE_CA_1 for SIM slot 1 (second SIM) + * + * Type: int (0 = disabled, 1 = enabled) + * @hide + */ + public static final String FORCE_LTE_CA = "force_lte_ca"; + + /** + * Force LTE Carrier Aggregation for SIM slot 0 + * Type: int (0 = disabled, 1 = enabled) + * @hide + */ + public static final String FORCE_LTE_CA_0 = "force_lte_ca_0"; + + /** + * Force LTE Carrier Aggregation for SIM slot 1 + * Type: int (0 = disabled, 1 = enabled) + * @hide + */ + public static final String FORCE_LTE_CA_1 = "force_lte_ca_1"; + /** * Name of an application package to be debugged. */ @@ -19098,6 +20716,12 @@ public static final class Global extends NameValueTable { */ public static final String ONE_HANDED_KEYGUARD_SIDE = "one_handed_keyguard_side"; + /** + * Whether refresh rate should be switched to 60Hz on power save mode. + * @hide + */ + public static final String LOW_POWER_REFRESH_RATE = "low_power_rr_switch"; + /** * A list of uids that are allowed to use restricted networks. * @@ -19164,6 +20788,32 @@ public static final class Global extends NameValueTable { CLOCKWORK_HOME_READY, }; + /** + * The amount of time in milliseconds before wifi is turned off + * @hide + */ + public static final String WIFI_OFF_TIMEOUT = "wifi_off_timeout"; + + /** + * The amount of time in milliseconds before bluetooth is turned off + * @hide + */ + public static final String BLUETOOTH_OFF_TIMEOUT = "bluetooth_off_timeout"; + + /** + * Sensor block per-package + * @hide + */ + @Readable + public static final String SENSOR_BLOCK = "sensor_block"; + + /** + * Sensor blocked packages + * @hide + */ + @Readable + public static final String SENSOR_BLOCKED_APP = "sensor_blocked_app"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. @@ -20298,6 +21948,31 @@ public static boolean putFloat(ContentResolver cr, String name, float value) { */ public static final String RESTRICTED_NETWORKING_MODE = "restricted_networking_mode"; + /** + * Control whether FLAG_SECURE is ignored for all windows. + * @hide + */ + @Readable + public static final String WINDOW_IGNORE_SECURE = "window_ignore_secure"; + + /** + * Control whether application downgrade is allowed. + * @hide + */ + public static final String PM_DOWNGRADE_ALLOWED = "pm_downgrade_allowed"; + + /** + * Control whether to hide screen capture status from apps. + * @hide + */ + public static final String HIDE_SCREEN_CAPTURE_STATUS = "hide_screen_capture_status"; + + /** + * Control whether to remove the restriction when selecting folders through SAF. + * @hide + */ + public static final String NO_STORAGE_RESTRICT = "no_storage_restrict"; + /** * Setting indicating whether Low Power Standby is enabled, if supported. * @@ -21717,6 +23392,9 @@ public static Map getStrings(@NonNull ContentResolver resolver, @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean putString(@NonNull String namespace, @NonNull String name, @Nullable String value, boolean makeDefault) { + if (DeviceConfigUtils.shouldDenyDeviceConfigControl(namespace, name)) { + return true; + } ContentResolver resolver = getContentResolver(); return sNameValueCache.putStringForUser(resolver, createCompositeName(namespace, name), value, null, makeDefault, resolver.getUserId(), @@ -21738,7 +23416,9 @@ public static boolean putString(@NonNull String namespace, public static boolean setStrings(@NonNull String namespace, @NonNull Map keyValues) throws DeviceConfig.BadConfigException { - return setStrings(getContentResolver(), namespace, keyValues); + boolean result = setStrings(getContentResolver(), namespace, keyValues); + DeviceConfigUtils.setDefaultProperties(namespace, null); + return result; } /** @@ -21788,6 +23468,9 @@ public static boolean setStrings(@NonNull ContentResolver resolver, @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean deleteString(@NonNull String namespace, @NonNull String name) { + if (DeviceConfigUtils.shouldDenyDeviceConfigControl(namespace, name)) { + return true; + } ContentResolver resolver = getContentResolver(); return sNameValueCache.deleteStringForUser(resolver, createCompositeName(namespace, name), resolver.getUserId()); @@ -21829,6 +23512,7 @@ public static void resetToDefaults(@ResetMode int resetMode, } catch (RemoteException e) { Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI, e); } + DeviceConfigUtils.setDefaultProperties(null, null); } /** @@ -22321,6 +24005,12 @@ private Panel() { @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_VOLUME = "android.settings.panel.action.VOLUME"; + + /** + * @hide + */ + public static final String ACTION_APP_VOLUME = + "android.settings.panel.action.APP_VOLUME"; } /** diff --git a/core/java/android/security/gameprops/GamePropsSpoofService.java b/core/java/android/security/gameprops/GamePropsSpoofService.java new file mode 100644 index 0000000000000..a6cbb8ae86ffd --- /dev/null +++ b/core/java/android/security/gameprops/GamePropsSpoofService.java @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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 android.security.gameprops; + +import android.app.ActivityManager; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Build; +import android.os.RemoteException; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.JsonReader; +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Unified device-props spoofing service. + * + * Handles two independent sources: + * + * 1. JSON game-props config (stored in Settings.Secure via system_server) — the original + * GamePropsSpoofService behaviour, keyed by package name with arbitrary Build field maps. + * + * 2. Per-app spoof map (stored in Settings.Secure.PER_APPS_DEVICE_SPOOF) — formerly + * PerAppsPropsUtils, maps a package name to a named device profile (e.g. "ROG8P"). + * Requires a Context to read Settings.Secure at spoof time. + * + * Source (1) takes priority: if a package has a JSON game-props entry that entry is applied + * and per-app lookup is skipped for that package. + * + * @hide + */ +public final class GamePropsSpoofService { + + private static final String TAG = "GameProps"; + + // ------------------------------------------------------------------------- + // Settings keys (mirrors Settings.Secure constants used by the UI) + // ------------------------------------------------------------------------- + + /** Comma-separated "pkg:profileId" pairs for the active per-app spoof map. */ + private static final String SETTING_PER_APPS = "per_apps_device_spoof"; + /** Master enable flag for per-app spoofing (int, default 1). */ + private static final String SETTING_PER_APPS_ENABLED = "per_apps_device_spoof_enabled"; + /** JSON array of custom user-defined profiles. */ + private static final String SETTING_CUSTOM_PROFILES = "custom_spoof_profiles"; + + // ------------------------------------------------------------------------- + // Singleton + // ------------------------------------------------------------------------- + + private static GamePropsSpoofService sInstance; + + private GamePropsSpoofService() {} + + /** @hide */ + public static synchronized GamePropsSpoofService getInstance() { + if (sInstance == null) { + sInstance = new GamePropsSpoofService(); + sInstance.loadConfig(); + } + return sInstance; + } + + // ------------------------------------------------------------------------- + // JSON game-props state (source 1) + // ------------------------------------------------------------------------- + + private volatile boolean mEnabled = false; + private volatile boolean mDebug = false; + private volatile boolean mConfigLoaded = false; + + /** packageName → { fieldName → value } from JSON game-props config */ + private final Map> mGameConfigs = new ConcurrentHashMap<>(); + + // ------------------------------------------------------------------------- + // Built-in device profiles (formerly in PerAppsPropsUtils static block) + // ------------------------------------------------------------------------- + + /** + * Built-in named profiles. Keys match the profile IDs used by + * UserSelectedAppSpoofSettings / PerAppsPropsUtils. + * + * @hide + */ + public static final Map> BUILTIN_PROFILES; + + static { + BUILTIN_PROFILES = new HashMap<>(); + BUILTIN_PROFILES.put("BS4C", profile("Black Shark", "2SM-X706B", "Xiaomi", "2SM-X706B", "BlackShark/PRS-H0/Black Shark 4:13/TQ3A.230805.001/20230315:user/release-keys", "2SM-X706B")); + BUILTIN_PROFILES.put("F5", profile("Xiaomi", "23049PCD8G", "Xiaomi", "marble", "Xiaomi/marble_global/marble:14/UKQ1.230917.001/V816.0.2.0.UMRMIXM:user/release-keys", "marble")); + BUILTIN_PROFILES.put("GZF5", profile("samsung", "SM-F9460", "samsung", "Galaxy Z Fold 5", "samsung/q2qzh/q2q:15/UP1A.231005.007/F946BXXU1BWK4:user/release-keys", "SM-F9460")); + BUILTIN_PROFILES.put("HMV2R", profile("HONOR", "VER-N49DP", "HONOR", "Honor Magic V2 RSR", "HONOR/VER-N49DP/VER:13/ENG.20240918.123456:user/release-keys", "VER-N49DP")); + BUILTIN_PROFILES.put("LY700", profile("Lenovo", "Lenovo TB-9707F", "Lenovo", "Lenovo Y700", null, null)); + BUILTIN_PROFILES.put("LY70023", profile("Lenovo", "TB-9707F", "Lenovo", "Legion Y700 (2023)", "Lenovo/TB-9707F/Lenovo TB-9707F:13/TQ3A.230805.001/20230901:user/release-keys", "TB-9707F")); + BUILTIN_PROFILES.put("MI11TP", profile("Xiaomi", "2107113SG", "Xiaomi", "Xiaomi 11T Pro", "Xiaomi/2107113SI/Mi 11T Pro:13/RKQ1.211001.001/20230410:user/release-keys", "2107113SG")); + BUILTIN_PROFILES.put("MI13", profile("Xiaomi", "2211133G", "Xiaomi", "Xiaomi 13", "Xiaomi/fuxi_eea/fuxi:13/TKQ1.221114.001/OS2.0.102.0.VMCEUXM:user/release-keys", "2211133G")); + BUILTIN_PROFILES.put("MI13P", profile("Xiaomi", "2210132G", "Xiaomi", "Xiaomi 13 Pro", "Xiaomi/fuxi_eea/fuxi:13/TKQ1.221114.001/OS2.0.102.0.VMCEUXM:user/release-keys", "2210132G")); + BUILTIN_PROFILES.put("MI14P", profile("Xiaomi", "23116PN5BC", "Xiaomi", "houji", "Xiaomi/houji/houji:14/UKQ1.230917.001/V816.0.2.0.UNBCNXM:user/release-keys", "houji")); + BUILTIN_PROFILES.put("OP12", profile("OnePlus", "CPH2581", "OnePlus", "OP594DL1", "OnePlus/OP594DL1/OP594DL1:14/UKQ1.230917.001/1702951307528:user/release-keys", "OP594DL1")); + BUILTIN_PROFILES.put("OP13", profile("OnePlus", "PJZ110", "OnePlus", "OnePlus 13", "OnePlus/PJZ110/OP5D0DL1:15/AP3A.240617.008/V.1bd19a1-1-2:user/release-keys", "PJZ110")); + BUILTIN_PROFILES.put("OP8P5G", profile("OnePlus", "IN2023", "OnePlus", "OnePlus 8 Pro 5G", "OnePlus/IN2023/OnePlus8Pro:13/RKQ1.211119.001/20230501:user/release-keys", "IN2023")); + BUILTIN_PROFILES.put("PXL", profile("google", "marlin", "Google", "Pixel XL", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys", "marlin")); + BUILTIN_PROFILES.put("PXL10PXL",profile("google", "Pixel 10 Pro XL", "Google", "mustang", "google/mustang/mustang:16/CP1A.260305.018/14887507:user/release-keys", "mustang")); + BUILTIN_PROFILES.put("RM9P", profile("nubia", "NX769J", "ZTE", "REDMAGIC 9 Pro", "nubia/NX769J/NX769J:14/UKQ1.230917.001/20240813.173312:user/release-keys", "NX769J")); + BUILTIN_PROFILES.put("RM10P", profile("nubia", "NX789J", "ZTE", "RedMagic 10 Pro", "nubia/NX789J-UN/NX789J:15/AQ3A.240812.002/20241212.194919:user/release-keys", "NX789J")); + BUILTIN_PROFILES.put("RM15P5G", profile("realme", "RMX5101", "realme", "Realme 15 Pro 5G", "realme/RMX5101IN/RE60B4L1:15/AP3A.240617.008/V.R4T2.26cec0e-80bb4e-80b757:user/release-keys", "RMX5101")); + BUILTIN_PROFILES.put("RMX14", profile("realme", "RMX5070", "realme", "Realme 14", null, null)); + BUILTIN_PROFILES.put("RMP35G", profile("realme", "RMX5070", "realme", "Realme P3 5G", "realme/RMX5070/RMX5070:15/SKQ1.230119.001/eng.user.20250415.155201:user/release-keys", "RMX5070")); + BUILTIN_PROFILES.put("ROG6DU", profile("ASUS", "AI2203", "ASUS", "ROG Phone 6D Ultimate", "ASUS/AI2203/ROG Phone 6D:14/UP1A.231005.007/20240315:user/release-keys", "AI2203")); + BUILTIN_PROFILES.put("ROG8P", profile("asus", "ASUS_AI2401_D", "asus", "ASUS_AI2401_D", "asus/ASUS_AI2401_D/ASUS_AI2401:14/UKQ1.230804.001/34.0210.0210.222-0:user/release-keys", "ASUS_AI2401_D")); + BUILTIN_PROFILES.put("ROG9P", profile("Asus", "ASUS_AI2501", "Asus", "ROG Phone 9 PRO", null, null)); + BUILTIN_PROFILES.put("S25U", profile("Samsung", "SM-S938B", "samsung", "Samsung S25 Ultra", null, null)); + } + + /** Convenience builder for a profile map. Null fp/product are skipped. */ + private static Map profile(String brand, String model, String manufacturer, + String device, String fingerprint, String product) { + Map m = new HashMap<>(); + m.put("BRAND", brand); + m.put("MODEL", model); + m.put("MANUFACTURER", manufacturer); + m.put("DEVICE", device); + if (fingerprint != null) m.put("FINGERPRINT", fingerprint); + if (product != null) m.put("PRODUCT", product); + return m; + } + + // ------------------------------------------------------------------------- + // JSON config loading (source 1) + // ------------------------------------------------------------------------- + + /** @hide */ + public void loadConfig() { + mGameConfigs.clear(); + mEnabled = false; + mConfigLoaded = false; + + String content; + try { + content = ActivityManager.getService().getSpoofGamePropsConfig(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to fetch gameprops config from system_server", e); + return; + } + + if (content == null || content.isEmpty()) { + Log.w(TAG, "No gameprops config in Settings.Secure"); + return; + } + + try { + parseJson(content); + mConfigLoaded = true; + Log.i(TAG, "Game props config loaded, games=" + mGameConfigs.size() + + ", enabled=" + mEnabled); + } catch (Exception e) { + Log.e(TAG, "Failed to parse game props config", e); + } + } + + private void parseJson(String content) { + try (JsonReader reader = new JsonReader(new StringReader(content))) { + reader.beginObject(); + while (reader.hasNext()) { + String key = reader.nextName(); + if ("enabled".equals(key)) { + mEnabled = reader.nextBoolean(); + } else if ("debug".equals(key)) { + mDebug = reader.nextBoolean(); + } else if ("games".equals(key)) { + parseGames(reader); + } else { + reader.skipValue(); + } + } + reader.endObject(); + } catch (Exception e) { + Log.e(TAG, "Failed to parse JSON config", e); + } + } + + private void parseGames(JsonReader reader) throws IOException { + reader.beginObject(); + while (reader.hasNext()) { + String packageName = reader.nextName(); + Map gameProps = new HashMap<>(); + reader.beginObject(); + while (reader.hasNext()) { + gameProps.put(reader.nextName(), reader.nextString()); + } + reader.endObject(); + if (!gameProps.isEmpty()) { + mGameConfigs.put(packageName, gameProps); + if (mDebug) Log.d(TAG, "Loaded config for " + packageName + + ": " + gameProps.size() + " props"); + } + } + reader.endObject(); + } + + // ------------------------------------------------------------------------- + // Public spoof entry points + // ------------------------------------------------------------------------- + + /** + * Apply spoofing for the given package. + * + * Checks JSON game-props first (source 1). If no entry is found there, + * falls back to the per-app Settings.Secure map (source 2) when a Context + * is supplied. + * + * @hide + */ + public void spoofForPackage(String packageName, Context context) { + if (packageName == null) return; + + // Source 1 — JSON game-props config + if (mEnabled && mConfigLoaded) { + Map gameProps = mGameConfigs.get(packageName); + if (gameProps != null && !gameProps.isEmpty()) { + if (mDebug) Log.d(TAG, "Spoofing via game-props for: " + packageName); + for (Map.Entry entry : gameProps.entrySet()) { + spoofField(entry.getKey(), entry.getValue(), packageName); + } + return; // source 1 wins; skip per-app lookup + } + } + + // Source 2 — per-app Settings.Secure map (formerly PerAppsPropsUtils) + if (context != null) { + applyPerAppSpoof(packageName, context); + } + } + + /** + * Convenience overload for callers that only have the JSON game-props path + * (no Context available). + * + * @hide + */ + public void spoofForPackage(String packageName) { + spoofForPackage(packageName, null); + } + + // ------------------------------------------------------------------------- + // Per-app spoof logic (source 2 — formerly PerAppsPropsUtils.setProps) + // ------------------------------------------------------------------------- + + private void applyPerAppSpoof(String packageName, Context context) { + // Check master enable flag + try { + int enabled = Settings.Secure.getInt( + context.getContentResolver(), SETTING_PER_APPS_ENABLED, 1); + if (enabled == 0) return; + } catch (Exception e) { + if (mDebug) Log.d(TAG, "Could not read per-apps enabled flag: " + e.getMessage()); + return; + } + + // Read active map: "pkg1:profileId1,pkg2:profileId2,..." + String spoofedApps; + try { + spoofedApps = Settings.Secure.getString( + context.getContentResolver(), SETTING_PER_APPS); + } catch (Exception e) { + if (mDebug) Log.d(TAG, "Failed to read per-apps setting: " + e.getMessage()); + return; + } + + if (TextUtils.isEmpty(spoofedApps)) return; + + // Find this package's assigned profile ID + String profileId = null; + for (String entry : spoofedApps.split(",")) { + String[] parts = entry.split(":"); + if (parts.length == 2 && packageName.equals(parts[0])) { + profileId = parts[1]; + break; + } + } + if (profileId == null) return; + + // Build combined profile map: built-ins + custom user profiles + Map> allProfiles = new HashMap<>(BUILTIN_PROFILES); + loadCustomProfiles(context, allProfiles); + + Map props = allProfiles.get(profileId); + if (props == null) { + if (mDebug) Log.d(TAG, "Unknown profile id '" + profileId + + "' for package " + packageName); + return; + } + + if (mDebug) Log.d(TAG, "Per-app spoof: " + packageName + " → " + profileId); + for (Map.Entry prop : props.entrySet()) { + Object v = prop.getValue(); + if (v != null) spoofField(prop.getKey(), v.toString(), packageName); + } + } + + /** + * Reads custom profiles from Settings.Secure and merges them into {@code out}. + * Any profile whose id collides with a built-in is skipped (built-ins win). + */ + private void loadCustomProfiles(Context context, Map> out) { + String json; + try { + json = Settings.Secure.getString( + context.getContentResolver(), SETTING_CUSTOM_PROFILES); + } catch (Exception e) { + return; + } + if (TextUtils.isEmpty(json)) return; + + try { + JSONArray arr = new JSONArray(json); + for (int i = 0; i < arr.length(); i++) { + JSONObject obj = arr.getJSONObject(i); + String id = obj.getString("id"); + if (out.containsKey(id)) continue; // built-in takes priority + + Map props = new HashMap<>(); + props.put("BRAND", obj.optString("brand", "")); + props.put("MANUFACTURER", obj.optString("manufacturer", "")); + props.put("DEVICE", obj.optString("device", "")); + props.put("MODEL", obj.optString("model", "")); + String fp = obj.optString("fingerprint", ""); + String prod = obj.optString("product", ""); + if (!TextUtils.isEmpty(fp)) props.put("FINGERPRINT", fp); + if (!TextUtils.isEmpty(prod)) props.put("PRODUCT", prod); + out.put(id, props); + } + } catch (Exception e) { + Log.e(TAG, "Failed to parse custom spoof profiles", e); + } + } + + // ------------------------------------------------------------------------- + // Reflection helpers + // ------------------------------------------------------------------------- + + private void spoofField(String fieldName, String value, String packageName) { + if (value == null || value.isEmpty()) { + if (mDebug) Log.d(TAG, fieldName + " is empty, skipping"); + return; + } + try { + Field field = getDeclaredField(Build.class, fieldName); + if (field == null) field = getDeclaredField(Build.VERSION.class, fieldName); + if (field == null) { + if (mDebug) Log.d(TAG, "Field not found: " + fieldName); + return; + } + + field.setAccessible(true); + String oldValue = String.valueOf(field.get(null)); + if (value.equals(oldValue)) { + if (mDebug) Log.d(TAG, "[" + fieldName + "]: " + value + " (unchanged)"); + return; + } + + Class type = field.getType(); + Object newValue; + if (type == String.class) newValue = value; + else if (type == int.class) newValue = Integer.parseInt(value); + else if (type == long.class) newValue = Long.parseLong(value); + else if (type == boolean.class) newValue = Boolean.parseBoolean(value); + else { + Log.w(TAG, "Unsupported field type: " + type); + return; + } + + field.set(null, newValue); + if (mDebug) Log.d(TAG, "[" + packageName + "][" + fieldName + "]: " + + oldValue + " → " + value); + + } catch (Exception e) { + Log.e(TAG, "Failed to spoof " + fieldName + " for " + packageName, e); + } + } + + private static Field getDeclaredField(Class clazz, String name) { + try { + return clazz.getDeclaredField(name); + } catch (NoSuchFieldException e) { + return null; + } + } + + // ------------------------------------------------------------------------- + // Accessors (unchanged public API) + // ------------------------------------------------------------------------- + + /** @hide */ + public boolean isEnabled() { + return mEnabled && mConfigLoaded; + } + + /** @hide */ + public boolean hasConfigForPackage(String packageName) { + return mGameConfigs.containsKey(packageName); + } + + /** @hide */ + public Map> getAllGameConfigs() { + return new ConcurrentHashMap<>(mGameConfigs); + } + + /** @hide */ + public boolean isConfigLoaded() { + return mConfigLoaded; + } +} diff --git a/core/java/android/security/pif/PlayIntegritySpoofService.java b/core/java/android/security/pif/PlayIntegritySpoofService.java new file mode 100644 index 0000000000000..3c28e450cbbbe --- /dev/null +++ b/core/java/android/security/pif/PlayIntegritySpoofService.java @@ -0,0 +1,523 @@ +package android.security.pif; + +import android.app.ActivityManager; +import android.app.ActivityThread; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.text.TextUtils; +import android.util.Base64; +import android.util.JsonReader; +import android.util.Log; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** @hide */ +public final class PlayIntegritySpoofService { + private static final String TAG = "PIF"; + + private static final String DROIDGUARD_PACKAGE = "com.google.android.gms.unstable"; + private static final String VENDING_PACKAGE = "com.android.vending"; + private static final String GMS_PACKAGE = "com.google.android.gms"; + + private static final String ROM_SIGNATURE_DATA = "MIIFyTCCA7GgAwIBAgIVALyxxl+zDS9SL68SzOr48309eAZyMA0GCSqGSIb3DQEBCwUAMHQxCzAJ" + + "BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQw" + + "EgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAg" + + "Fw0yMjExMDExODExMzVaGA8yMDUyMTEwMTE4MTEzNVowdDELMAkGA1UEBhMCVVMxEzARBgNVBAgT" + + "CkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC0dvb2dsZSBJbmMu" + + "MRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQDEwdBbmRyb2lkMIICIjANBgkqhkiG9w0BAQEFAAOC" + + "Ag8AMIICCgKCAgEAsqtalIy/nctKlrhd1UVoDffFGnDf9GLi0QQhsVoJkfF16vDDydZJOycG7/kQ" + + "ziRZhFdcoMrIYZzzw0ppBjsSe1AiWMuKXwTBaEtxN99S1xsJiW4/QMI6N6kMunydWRMsbJ6aAxi1" + + "lVq0bxSwr8Sg/8u9HGVivfdG8OpUM+qjuV5gey5xttNLK3BZDrAlco8RkJZryAD40flmJZrWXJmc" + + "r2HhJJUnqG4Z3MSziEgW1u1JnnY3f/BFdgYsA54SgdUGdQP3aqzSjIpGK01/vjrXvifHazSANjvl" + + "0AUE5i6AarMw2biEKB2ySUDp8idC5w12GpqDrhZ/QkW8yBSa87KbkMYXuRA2Gq1fYbQx3YJraw0U" + + "gZ4M3fFKpt6raxxM5j0sWHlULD7dAZMERvNESVrKG3tQ7B39WAD8QLGYc45DFEGOhKv5Fv8510h5" + + "sXK502IvGpI4FDwz2rbtAgJ0j+16db5wCSW5ThvNPhCheyciajc8dU1B5tJzZN/ksBpzne4Xf9gO" + + "LZ9ZU0+3Z5gHVvTS/YpxBFwiFpmL7dvGxew0cXGSsG5UTBlgr7i0SX0WhY4Djjo8IfPwrvvA0QaC" + + "FamdYXKqBsSHgEyXS9zgGIFPt2jWdhaS+sAa//5SXcWro0OdiKPuwEzLgj759ke1sHRnvO735dYn" + + "5whVbzlGyLBh3L0CAwEAAaNQME4wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUU1eXQ7NoYKjvOQlh" + + "5V8jHQMoxA8wHwYDVR0jBBgwFoAUU1eXQ7NoYKjvOQlh5V8jHQMoxA8wDQYJKoZIhvcNAQELBQAD" + + "ggIBAHFIazRLs3itnZKllPnboSd6sHbzeJURKehx8GJPvIC+xWlwWyFO5+GHmgc3yh/SVd3Xja/k" + + "8Ud59WEYTjyJJWTw0Jygx37rHW7VGn2HDuy/x0D+els+S8HeLD1toPFMepjIXJn7nHLhtmzTPlDW" + + "DrhiaYsls/k5Izf89xYnI4euuOY2+1gsweJqFGfbznqyqy8xLyzoZ6bvBJtgeY+G3i/9Be14HseS" + + "Na4FvI1Oze/l2gUu1IXzN6DGWR/lxEyt+TncJfBGKbjafYrfSh3zsE4N3TU7BeOL5INirOMjre/j" + + "VgB1YQG5qLVaPoz6mdn75AbBBm5a5ahApLiKqzy/hP+1rWgw8Ikb7vbUqov/bnY3IlIU6XcPJTCD" + + "b9aRZQkStvYpQd82XTyxD/T0GgRLnUj5Uv6iZlikFx1KNj0YNS2T3gyvL++J9B0Y6gAkiG0EtNpl" + + "z7Pomsv5pVdmHVdKMjqWw5/6zYzVmu5cXFtR384Ti1qwML1xkD6TC3VIv88rKIEjrkY2c+v1frh9" + + "fRJ2OmzXmML9NgHTjEiJR2Ib2iNrMKxkuTIs9oxKZgrJtJKvdU9qJJKM5PnZuNuHhGs6A/9gt9Oc" + + "cetYeQvVSqeEmQluWfcunQn9C9Vwi2BJIiVJh4IdWZf5/e2PlSSQ9CJjz2bKI17pzdxOmjQfE0JS" + + "F7Xt"; + + private static PlayIntegritySpoofService sInstance; + + private volatile int mVerboseLogs = 0; + private volatile boolean mSpoofBuild = true; + private volatile boolean mSpoofProps = true; + private volatile boolean mSpoofProvider = true; + private volatile boolean mSpoofSignature = false; + private volatile boolean mSpoofVendingBuild = true; + private volatile boolean mSpoofVendingSdk = false; + private volatile boolean mDebug = false; + + private final Map mBuildFields = new ConcurrentHashMap<>(); + private final Map mSystemProps = new ConcurrentHashMap<>(); + + private volatile boolean mConfigLoaded = false; + private volatile boolean mSignatureSpoofed = false; + + private PlayIntegritySpoofService() {} + + public static synchronized PlayIntegritySpoofService getInstance() { + if (sInstance == null) { + sInstance = new PlayIntegritySpoofService(); + sInstance.loadConfig(); + } + return sInstance; + } + + public void loadConfig() { + mBuildFields.clear(); + mSystemProps.clear(); + mConfigLoaded = false; + + String content; + try { + content = ActivityManager.getService().getSpoofPifConfig(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to fetch PIF config from system_server", e); + return; + } + + if (content == null || content.isEmpty()) { + Log.w(TAG, "No PIF config in Settings.Secure"); + return; + } + + try { + String trimmed = content.trim(); + if (trimmed.startsWith("{")) { + parseJson(content); + } else { + parseProp(content); + } + + mConfigLoaded = true; + Log.i(TAG, "PIF config loaded, fields=" + mBuildFields.size() + + ", props=" + mSystemProps.size()); + + // Sync SECURITY_PATCH to system props so apps reading these directly + // see the spoofed date, matching what the upstream module does via resetprop. + String secPatch = mBuildFields.get("SECURITY_PATCH"); + if (secPatch != null && !secPatch.isEmpty()) { + mSystemProps.put("ro.build.version.security_patch", secPatch); + mSystemProps.put("ro.vendor.build.security_patch", secPatch); + } + } catch (Exception e) { + Log.e(TAG, "Failed to load PIF config", e); + } + } + + private void parseProp(String content) { + String[] lines = content.split("\n"); + for (String line : lines) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) continue; + + int eqIdx = line.indexOf('='); + if (eqIdx <= 0) continue; + + String key = line.substring(0, eqIdx).trim(); + String value = line.substring(eqIdx + 1).trim(); + + int commentIdx = value.indexOf('#'); + if (commentIdx >= 0) { + value = value.substring(0, commentIdx).trim(); + } + + if (value.isEmpty()) continue; + + processKeyValue(key, value); + } + } + + private void parseJson(String content) { + try (JsonReader reader = new JsonReader(new StringReader(content))) { + reader.beginObject(); + while (reader.hasNext()) { + String key = reader.nextName(); + String value; + switch (reader.peek()) { + case BOOLEAN: + value = String.valueOf(reader.nextBoolean()); + break; + case NUMBER: + value = reader.nextString(); + break; + case NULL: + reader.nextNull(); + continue; + default: + value = reader.nextString(); + break; + } + processKeyValue(key, value); + } + reader.endObject(); + } catch (Exception e) { + Log.e(TAG, "Failed to parse JSON config", e); + } + } + + private void processKeyValue(String key, String value) { + switch (key) { + case "verboseLogs": + case "VERBOSE_LOGS": + try { + mVerboseLogs = Integer.parseInt(value); + } catch (NumberFormatException e) { + mVerboseLogs = 0; + } + break; + case "spoofBuild": + mSpoofBuild = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "spoofProps": + mSpoofProps = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "spoofProvider": + mSpoofProvider = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "spoofSignature": + mSpoofSignature = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "spoofVendingBuild": + mSpoofVendingBuild = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "spoofVendingSdk": + mSpoofVendingSdk = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + case "DEBUG": + mDebug = "1".equals(value) || "true".equalsIgnoreCase(value); + break; + default: + if (key.contains(".") || key.startsWith("*")) { + mSystemProps.put(key, value); + } else { + mBuildFields.put(key, value); + } + break; + } + } + + public boolean shouldSpoof(String processName) { + if (!mConfigLoaded) return false; + return DROIDGUARD_PACKAGE.equals(processName) || VENDING_PACKAGE.equals(processName); + } + + public boolean isGmsProcess(String dataDir) { + if (dataDir == null) return false; + return dataDir.endsWith("/" + GMS_PACKAGE) || dataDir.endsWith("/" + VENDING_PACKAGE); + } + + public boolean isDroidGuard(String processName) { + return DROIDGUARD_PACKAGE.equals(processName); + } + + public boolean isVending(String processName) { + return VENDING_PACKAGE.equals(processName); + } + + public void spoofBuildFields(String processName) { + if (!mConfigLoaded) return; + + boolean isVending = isVending(processName); + boolean isDroidGuard = isDroidGuard(processName); + + if (!isDroidGuard && !isVending) return; + + if (isVending) { + if (!mSpoofVendingBuild) { + if (mVerboseLogs > 0) Log.d(TAG, "Vending build spoofing disabled"); + return; + } + for (Map.Entry entry : mBuildFields.entrySet()) { + if ("SDK_INT".equals(entry.getKey())) continue; + spoofField(entry.getKey(), entry.getValue(), "PS"); + } + return; + } + + if (!mSpoofBuild) { + if (mVerboseLogs > 0) Log.d(TAG, "Build spoofing disabled"); + return; + } + + for (Map.Entry entry : mBuildFields.entrySet()) { + spoofField(entry.getKey(), entry.getValue(), "DG"); + } + + // spoofVendingSdk when enabled applies an additional SDK_INT override + // specifically for DroidGuard to match legacy attestation paths. + // It has no effect on Vending. + if (mSpoofVendingSdk) { + spoofSdkInt(); + } + } + + public void spoofSignature() { + if (!mSpoofSignature || mSignatureSpoofed) return; + + Signature spoofedSignature = new Signature(Base64.decode(ROM_SIGNATURE_DATA, Base64.DEFAULT)); + Parcelable.Creator originalCreator = PackageInfo.CREATOR; + Parcelable.Creator customCreator = new CustomPackageInfoCreator(originalCreator, spoofedSignature); + + try { + Field creatorField = findField(PackageInfo.class, "CREATOR"); + creatorField.setAccessible(true); + creatorField.set(null, customCreator); + creatorField.setAccessible(false); + } catch (Exception e) { + Log.e(TAG, "Couldn't replace PackageInfoCreator: " + e); + return; + } + + try { + Field cacheField = findField(PackageManager.class, "sPackageInfoCache"); + cacheField.setAccessible(true); + Object cache = cacheField.get(null); + if (cache != null) { + Method clearMethod = cache.getClass().getMethod("clear"); + clearMethod.invoke(cache); + } + cacheField.setAccessible(false); + } catch (Exception e) { + if (mDebug) Log.d(TAG, "Couldn't clear PackageInfoCache: " + e); + } + + try { + Field creatorsField = findField(Parcel.class, "mCreators"); + creatorsField.setAccessible(true); + Map mCreators = (Map) creatorsField.get(null); + if (mCreators != null) mCreators.clear(); + creatorsField.setAccessible(false); + } catch (Exception e) { + if (mDebug) Log.d(TAG, "Couldn't clear Parcel mCreators: " + e); + } + + try { + Field creatorsField = findField(Parcel.class, "sPairedCreators"); + creatorsField.setAccessible(true); + Map sPairedCreators = (Map) creatorsField.get(null); + if (sPairedCreators != null) sPairedCreators.clear(); + creatorsField.setAccessible(false); + } catch (Exception e) { + if (mDebug) Log.d(TAG, "Couldn't clear Parcel sPairedCreators: " + e); + } + + mSignatureSpoofed = true; + Log.i(TAG, "Signature spoofing enabled via Parcelable.Creator"); + } + + private Field findField(Class clazz, String fieldName) throws NoSuchFieldException { + Class currentClass = clazz; + while (currentClass != null && !currentClass.equals(Object.class)) { + try { + return currentClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + currentClass = currentClass.getSuperclass(); + } + } + throw new NoSuchFieldException("Field '" + fieldName + "' not found"); + } + + private void spoofSdkInt() { + // Only called for DroidGuard. Reads SDK_INT from config so it stays + // consistent with the spoofed fingerprint. Falls back to 32 if unset. + String configSdk = mBuildFields.get("SDK_INT"); + int targetSdk; + try { + targetSdk = (configSdk != null) ? Integer.parseInt(configSdk) : 32; + } catch (NumberFormatException e) { + targetSdk = 32; + } + + try { + Field field = Build.VERSION.class.getDeclaredField("SDK_INT"); + field.setAccessible(true); + int oldValue = field.getInt(null); + if (oldValue != targetSdk) { + field.set(null, targetSdk); + Log.d(TAG + "/Java:DG", "[SDK_INT]: " + oldValue + " -> " + targetSdk); + } + field.setAccessible(false); + } catch (Exception e) { + Log.e(TAG, "Failed to spoof SDK_INT", e); + } + } + + private void spoofField(String fieldName, String value, String logSuffix) { + if (value == null || value.isEmpty()) { + if (mVerboseLogs > 0) Log.d(TAG, fieldName + " is empty, skipping"); + return; + } + + try { + Field field; + String oldValue; + + if (hasField(Build.class, fieldName)) { + field = Build.class.getDeclaredField(fieldName); + } else if (hasField(Build.VERSION.class, fieldName)) { + field = Build.VERSION.class.getDeclaredField(fieldName); + } else { + if (mVerboseLogs > 1) Log.d(TAG, "Field not found: " + fieldName); + return; + } + + field.setAccessible(true); + oldValue = String.valueOf(field.get(null)); + + if (value.equals(oldValue)) { + if (mVerboseLogs > 2) Log.d(TAG, "[" + fieldName + "]: " + value + " (unchanged)"); + field.setAccessible(false); + return; + } + + Class fieldType = field.getType(); + Object newValue; + + if (fieldType == String.class) { + newValue = value; + } else if (fieldType == int.class) { + newValue = Integer.parseInt(value); + } else if (fieldType == long.class) { + newValue = Long.parseLong(value); + } else if (fieldType == boolean.class) { + newValue = Boolean.parseBoolean(value); + } else { + Log.w(TAG, "Unsupported field type: " + fieldType); + field.setAccessible(false); + return; + } + + field.set(null, newValue); + field.setAccessible(false); + + Log.d(TAG + "/Java:" + logSuffix, "[" + fieldName + "]: " + oldValue + " -> " + value); + + } catch (Exception e) { + Log.e(TAG, "Failed to spoof " + fieldName, e); + } + } + + private boolean hasField(Class clazz, String fieldName) { + for (Field f : clazz.getDeclaredFields()) { + if (f.getName().equals(fieldName)) return true; + } + return false; + } + + public String getSpoofedProperty(String key) { + if (!mSpoofProps || !mConfigLoaded) return null; + + String value = mSystemProps.get(key); + if (value != null) return value; + + for (Map.Entry entry : mSystemProps.entrySet()) { + String pattern = entry.getKey(); + if (pattern.startsWith("*") && key.endsWith(pattern.substring(1))) { + return entry.getValue(); + } + } + + return null; + } + + public boolean isSpoofSignatureEnabled() { + return mSpoofSignature && mConfigLoaded; + } + + public boolean isSpoofProviderEnabled() { + return mSpoofProvider && mConfigLoaded; + } + + public int getVerboseLogs() { + return mVerboseLogs; + } + + public Map getBuildFields() { + return mBuildFields; + } + + public Map getSystemProps() { + return mSystemProps; + } + + public boolean isConfigLoaded() { + return mConfigLoaded; + } + + public byte[] getRomSignatureBytes() { + return Base64.decode(ROM_SIGNATURE_DATA, Base64.DEFAULT); + } + + public void logBuildFields() { + if (mVerboseLogs < 100) return; + for (Field field : Build.class.getDeclaredFields()) { + try { + Log.d(TAG, "Build." + field.getName() + " = " + field.get(null)); + } catch (Exception e) { + } + } + for (Field field : Build.VERSION.class.getDeclaredFields()) { + try { + Log.d(TAG, "Build.VERSION." + field.getName() + " = " + field.get(null)); + } catch (Exception e) { + } + } + } + + private static class CustomPackageInfoCreator implements Parcelable.Creator { + private final Parcelable.Creator originalCreator; + private final Signature spoofedSignature; + + CustomPackageInfoCreator(Parcelable.Creator originalCreator, Signature spoofedSignature) { + this.originalCreator = originalCreator; + this.spoofedSignature = spoofedSignature; + } + + @Override + @SuppressWarnings("deprecation") + public PackageInfo createFromParcel(Parcel source) { + PackageInfo packageInfo = originalCreator.createFromParcel(source); + if ("android".equals(packageInfo.packageName)) { + if (packageInfo.signatures != null && packageInfo.signatures.length > 0) { + packageInfo.signatures[0] = spoofedSignature; + } + if (packageInfo.signingInfo != null) { + Signature[] signaturesArray = packageInfo.signingInfo.getApkContentsSigners(); + if (signaturesArray != null && signaturesArray.length > 0) { + signaturesArray[0] = spoofedSignature; + } + } + } + return packageInfo; + } + + @Override + public PackageInfo[] newArray(int size) { + return originalCreator.newArray(size); + } + } +} diff --git a/core/java/android/security/trickystore/AttestationUtils.java b/core/java/android/security/trickystore/AttestationUtils.java new file mode 100644 index 0000000000000..442463825f907 --- /dev/null +++ b/core/java/android/security/trickystore/AttestationUtils.java @@ -0,0 +1,300 @@ +package android.security.trickystore; + +import android.os.Build; +import android.os.SystemProperties; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.util.Log; + +import com.android.internal.org.bouncycastle.asn1.*; + +import java.io.ByteArrayInputStream; +import java.security.*; +import java.security.cert.*; + +/** + * @hide + */ +public final class AttestationUtils { + private static final String TAG = "AttestationUtils"; + + private static byte[] sBootKey; + private static byte[] sBootHash; + private static volatile boolean sTeeBroken = false; + + private AttestationUtils() {} + + public static void setTeeBroken(boolean broken) { + sTeeBroken = broken; + } + + public static boolean isTeeBroken() { + return sTeeBroken; + } + + public static byte[] getBootKey() { + if (sBootKey == null) { + sBootKey = generateRandomBytes(32); + } + return sBootKey; + } + + public static byte[] getBootHash() { + if (sBootHash == null) { + sBootHash = getBootHashFromProp(); + if (sBootHash == null && !sTeeBroken) { + sBootHash = extractBootHashFromTee(); + } + if (sBootHash == null) { + Log.w(TAG, "Failed to get boot hash from prop and TEE, using random bytes"); + sBootHash = generateRandomBytes(32); + } + } + return sBootHash; + } + + public static void initBootHash() { + Log.i(TAG, "initBootHash: Starting boot hash initialization"); + byte[] hash = getBootHashFromProp(); + if (hash != null) { + sBootHash = hash; + Log.i(TAG, "initBootHash: Boot hash already set from prop: " + bytesToHex(hash)); + return; + } + Log.i(TAG, "initBootHash: No prop set, attempting TEE extraction"); + hash = extractBootHashFromTee(); + if (hash != null) { + sBootHash = hash; + Log.i(TAG, "initBootHash: TEE extraction successful, setting prop"); + setVbmetaDigestProp(bytesToHex(hash)); + } else { + Log.e(TAG, "initBootHash: Failed to extract boot hash from TEE"); + } + } + + private static void setVbmetaDigestProp(String digest) { + try { + SystemProperties.set("ro.boot.vbmeta.digest", digest); + Log.i(TAG, "Set ro.boot.vbmeta.digest property to TEE boot hash"); + } catch (Exception e) { + Log.e(TAG, "Failed to set vbmeta.digest property", e); + } + } + + private static byte[] extractBootHashFromTee() { + try { + String alias = "trickystore_attestation_key"; + + KeyPairGenerator kpg = KeyPairGenerator.getInstance( + KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); + KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, + KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) + .setDigests(KeyProperties.DIGEST_SHA256) + .setAttestationChallenge(new byte[32]) + .build(); + kpg.initialize(spec); + kpg.generateKeyPair(); + + KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); + ks.load(null); + java.security.cert.Certificate[] chain = ks.getCertificateChain(alias); + + if (chain == null || chain.length == 0) { + Log.e(TAG, "No certificate chain from AndroidKeyStore"); + ks.deleteEntry(alias); + return null; + } + + X509Certificate leafCert = (X509Certificate) chain[0]; + byte[] extValue = leafCert.getExtensionValue("1.3.6.1.4.1.11129.2.1.17"); + + ks.deleteEntry(alias); + + if (extValue == null) { + Log.e(TAG, "No attestation extension in certificate"); + return null; + } + + ASN1InputStream ais = new ASN1InputStream(extValue); + ASN1OctetString octet = (ASN1OctetString) ais.readObject(); + ais.close(); + + ASN1InputStream seqStream = new ASN1InputStream(octet.getOctets()); + ASN1Sequence keyDesc = (ASN1Sequence) seqStream.readObject(); + seqStream.close(); + + ASN1Sequence teeEnforced = (ASN1Sequence) keyDesc.getObjectAt(7); + + for (int i = 0; i < teeEnforced.size(); i++) { + ASN1TaggedObject tagged = (ASN1TaggedObject) teeEnforced.getObjectAt(i); + if (tagged.getTagNo() == 704) { + ASN1Sequence rootOfTrust = (ASN1Sequence) tagged.getBaseObject(); + if (rootOfTrust.size() >= 4) { + ASN1OctetString bootHashOctet = (ASN1OctetString) rootOfTrust.getObjectAt(3); + byte[] hash = bootHashOctet.getOctets(); + Log.i(TAG, "Extracted boot hash from TEE: " + bytesToHex(hash)); + return hash; + } + } + } + + Log.e(TAG, "RootOfTrust not found in TEE enforced list"); + return null; + } catch (Exception e) { + Log.e(TAG, "Failed to extract boot hash from TEE", e); + return null; + } + } + + public static byte[] getBootHashFromProp() { + String digest = SystemProperties.get("ro.boot.vbmeta.digest", null); + if (digest == null || digest.isEmpty() || digest.length() != 64) { + return null; + } + try { + return hexStringToByteArray(digest); + } catch (Exception e) { + Log.e(TAG, "Failed to parse vbmeta.digest", e); + return null; + } + } + + public static int getOsVersion() { + switch (Build.VERSION.SDK_INT) { + case Build.VERSION_CODES.Q: return 100000; + case Build.VERSION_CODES.R: return 110000; + case Build.VERSION_CODES.S: return 120000; + case Build.VERSION_CODES.S_V2: return 120100; + case Build.VERSION_CODES.TIRAMISU: return 130000; + case Build.VERSION_CODES.UPSIDE_DOWN_CAKE: return 140000; + case Build.VERSION_CODES.VANILLA_ICE_CREAM: return 150000; + default: return 160000; + } + } + + public static int getAttestVersion() { + switch (Build.VERSION.SDK_INT) { + case Build.VERSION_CODES.Q: + case Build.VERSION_CODES.R: + return 4; + case Build.VERSION_CODES.S: + case Build.VERSION_CODES.S_V2: + return 100; + case Build.VERSION_CODES.TIRAMISU: + return 200; + case Build.VERSION_CODES.UPSIDE_DOWN_CAKE: + case Build.VERSION_CODES.VANILLA_ICE_CREAM: + return 300; + default: + return 400; + } + } + + public static int getKeymasterVersion() { + int attestVersion = getAttestVersion(); + return attestVersion == 4 ? 41 : attestVersion; + } + + public static int getPatchLevel(boolean isLong) { + TrickyStoreService.CustomPatchLevel customLevel = + TrickyStoreService.getInstance().getCustomPatchLevel(); + if (customLevel != null && customLevel.system != null) { + Integer parsed = parsePatchLevel(customLevel.system, isLong); + if (parsed != null) return parsed; + } + return convertPatchLevel(Build.VERSION.SECURITY_PATCH, isLong); + } + + public static int getVendorPatchLevel(boolean isLong) { + TrickyStoreService.CustomPatchLevel customLevel = + TrickyStoreService.getInstance().getCustomPatchLevel(); + if (customLevel != null && customLevel.vendor != null) { + Integer parsed = parsePatchLevel(customLevel.vendor, isLong); + if (parsed != null) return parsed; + } + return convertPatchLevel(Build.VERSION.SECURITY_PATCH, isLong); + } + + public static int getBootPatchLevel(boolean isLong) { + TrickyStoreService.CustomPatchLevel customLevel = + TrickyStoreService.getInstance().getCustomPatchLevel(); + if (customLevel != null && customLevel.boot != null) { + Integer parsed = parsePatchLevel(customLevel.boot, isLong); + if (parsed != null) return parsed; + } + return convertPatchLevel(Build.VERSION.SECURITY_PATCH, isLong); + } + + private static Integer parsePatchLevel(String value, boolean isLong) { + if (value == null || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("prop")) { + return null; + } + + String normalized = value.replace("-", ""); + try { + if (normalized.length() == 8) { + int year = Integer.parseInt(normalized.substring(0, 4)); + int month = Integer.parseInt(normalized.substring(4, 6)); + int day = Integer.parseInt(normalized.substring(6, 8)); + return isLong ? year * 10000 + month * 100 + day : year * 100 + month; + } else if (normalized.length() == 6) { + int year = Integer.parseInt(normalized.substring(0, 4)); + int month = Integer.parseInt(normalized.substring(4, 6)); + return isLong ? year * 10000 + month * 100 : year * 100 + month; + } + } catch (NumberFormatException e) { + Log.e(TAG, "Failed to parse patch level: " + value, e); + } + return null; + } + + public static int convertPatchLevel(String patchString, boolean isLong) { + try { + String[] parts = patchString.split("-"); + if (isLong && parts.length >= 3) { + return Integer.parseInt(parts[0]) * 10000 + + Integer.parseInt(parts[1]) * 100 + + Integer.parseInt(parts[2]); + } else if (parts.length >= 2) { + return Integer.parseInt(parts[0]) * 100 + Integer.parseInt(parts[1]); + } + } catch (Exception e) { + Log.e(TAG, "Invalid patch level format: " + patchString, e); + } + return 202404; + } + + public static byte[] computeModuleHash() { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + return digest.digest(new byte[0]); + } catch (Exception e) { + Log.e(TAG, "Failed to compute module hash", e); + return new byte[32]; + } + } + + private static byte[] generateRandomBytes(int length) { + byte[] bytes = new byte[length]; + new SecureRandom().nextBytes(bytes); + return bytes; + } + + private static byte[] hexStringToByteArray(String hex) { + int len = hex.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + + Character.digit(hex.charAt(i + 1), 16)); + } + return data; + } + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } +} diff --git a/core/java/android/security/trickystore/CertificateGenerator.java b/core/java/android/security/trickystore/CertificateGenerator.java new file mode 100644 index 0000000000000..5628adb01f2f6 --- /dev/null +++ b/core/java/android/security/trickystore/CertificateGenerator.java @@ -0,0 +1,342 @@ +package android.security.trickystore; + +import android.app.ActivityThread; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.content.pm.SigningInfo; +import android.util.Log; + +import com.android.internal.org.bouncycastle.asn1.ASN1Boolean; +import com.android.internal.org.bouncycastle.asn1.ASN1Encodable; +import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated; +import com.android.internal.org.bouncycastle.asn1.ASN1Integer; +import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.internal.org.bouncycastle.asn1.ASN1OctetString; +import com.android.internal.org.bouncycastle.asn1.DEROctetString; +import com.android.internal.org.bouncycastle.asn1.DERSequence; +import com.android.internal.org.bouncycastle.asn1.DERSet; +import com.android.internal.org.bouncycastle.asn1.DERTaggedObject; +import com.android.internal.org.bouncycastle.asn1.DERNull; +import com.android.internal.org.bouncycastle.asn1.x500.X500Name; +import com.android.internal.org.bouncycastle.asn1.x509.Extension; +import com.android.internal.org.bouncycastle.asn1.x509.KeyUsage; +import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.android.internal.org.bouncycastle.cert.X509CertificateHolder; +import com.android.internal.org.bouncycastle.cert.X509v3CertificateBuilder; +import com.android.internal.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.android.internal.org.bouncycastle.operator.ContentSigner; +import com.android.internal.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * @hide + */ +public final class CertificateGenerator { + private static final String TAG = "CertificateGenerator"; + + public static final ASN1ObjectIdentifier ATTESTATION_OID = + new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"); + + private CertificateGenerator() {} + + /** @hide */ + public static class KeyGenParameters { + public int keySize; + public int algorithm; + public BigInteger certificateSerial; + public Date certificateNotBefore; + public Date certificateNotAfter; + public X500Principal certificateSubject; + public BigInteger rsaPublicExponent; + public int ecCurve; + public String ecCurveName; + public List purpose = new ArrayList<>(); + public List digest = new ArrayList<>(); + public byte[] attestationChallenge; + public byte[] brand; + public byte[] device; + public byte[] product; + public byte[] manufacturer; + public byte[] model; + + public String getEcCurveName() { + if (ecCurveName != null) return ecCurveName; + switch (keySize) { + case 224: return "secp224r1"; + case 256: return "secp256r1"; + case 384: return "secp384r1"; + case 521: return "secp521r1"; + default: return "secp256r1"; + } + } + } + + public static KeyPair generateKeyPair(KeyGenParameters params) { + try { + KeyPairGenerator kpg; + if (params.algorithm == 3) { + kpg = KeyPairGenerator.getInstance("EC"); + kpg.initialize(new ECGenParameterSpec(params.getEcCurveName())); + } else if (params.algorithm == 1) { + kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(new RSAKeyGenParameterSpec( + params.keySize, + params.rsaPublicExponent != null ? params.rsaPublicExponent : RSAKeyGenParameterSpec.F4 + )); + } else { + Log.e(TAG, "Unsupported algorithm: " + params.algorithm); + return null; + } + return kpg.generateKeyPair(); + } catch (Exception e) { + Log.e(TAG, "Failed to generate key pair", e); + return null; + } + } + + public static List generateCertificateChain( + KeyPair keyPair, + KeyGenParameters params, + int securityLevel, + int uid) { + + KeyBoxManager keyboxManager = TrickyStoreService.getInstance().getKeyBoxManager(); + String algorithm = params.algorithm == 3 ? "EC" : "RSA"; + KeyBoxManager.KeyBox keybox = keyboxManager.getKeybox(algorithm); + + if (keybox == null) { + Log.e(TAG, "No keybox found for algorithm: " + algorithm); + return null; + } + + try { + X509CertificateHolder issuerHolder = new X509CertificateHolder( + keybox.certificates.get(0).getEncoded()); + X500Name issuer = issuerHolder.getSubject(); + + X509Certificate leaf = buildCertificate(keyPair, keybox, params, issuer, securityLevel, uid); + + List chain = new ArrayList<>(); + chain.add(leaf); + chain.addAll(keybox.certificates); + return chain; + } catch (Exception e) { + Log.e(TAG, "Failed to generate certificate chain", e); + return null; + } + } + + private static X509Certificate buildCertificate( + KeyPair keyPair, + KeyBoxManager.KeyBox keybox, + KeyGenParameters params, + X500Name issuer, + int securityLevel, + int uid) throws Exception { + + BigInteger serial = params.certificateSerial != null ? + params.certificateSerial : BigInteger.ONE; + Date notBefore = params.certificateNotBefore != null ? + params.certificateNotBefore : new Date(); + Date notAfter = params.certificateNotAfter != null ? + params.certificateNotAfter : + ((X509Certificate) keybox.certificates.get(0)).getNotAfter(); + X500Name subject = params.certificateSubject != null ? + X500Name.getInstance(params.certificateSubject.getEncoded()) : new X500Name("CN=Android Keystore Key"); + + SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance( + keyPair.getPublic().getEncoded()); + + X509v3CertificateBuilder builder = new X509v3CertificateBuilder( + issuer, + serial, + notBefore, + notAfter, + subject, + publicKeyInfo + ); + + builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign)); + builder.addExtension(buildAttestExtension(params, securityLevel, uid)); + + String sigAlg = params.algorithm == 3 ? "SHA256withECDSA" : "SHA256withRSA"; + JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(sigAlg); + if (params.algorithm == 3) { + signerBuilder.setProvider(new BouncyCastleProvider()); + } + ContentSigner signer = signerBuilder.build(keybox.keyPair.getPrivate()); + + X509CertificateHolder holder = builder.build(signer); + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certFactory.generateCertificate( + new ByteArrayInputStream(holder.getEncoded())); + } + + private static Extension buildAttestExtension(KeyGenParameters params, int securityLevel, int uid) { + try { + byte[] bootKey = AttestationUtils.getBootKey(); + byte[] bootHash = AttestationUtils.getBootHash(); + + ASN1Encodable[] rootOfTrustElements = new ASN1Encodable[] { + new DEROctetString(bootKey), + ASN1Boolean.TRUE, + new ASN1Enumerated(0), + new DEROctetString(bootHash) + }; + DERSequence rootOfTrust = new DERSequence(rootOfTrustElements); + + ASN1EncodableVector teeEnforced = new ASN1EncodableVector(); + + ASN1Integer[] purposes = new ASN1Integer[params.purpose.size()]; + for (int i = 0; i < params.purpose.size(); i++) { + purposes[i] = new ASN1Integer(params.purpose.get(i)); + } + teeEnforced.add(new DERTaggedObject(true, 1, new DERSet(purposes))); + teeEnforced.add(new DERTaggedObject(true, 2, new ASN1Integer(params.algorithm))); + teeEnforced.add(new DERTaggedObject(true, 3, new ASN1Integer(params.keySize))); + + ASN1Integer[] digests = new ASN1Integer[params.digest.size()]; + for (int i = 0; i < params.digest.size(); i++) { + digests[i] = new ASN1Integer(params.digest.get(i)); + } + teeEnforced.add(new DERTaggedObject(true, 5, new DERSet(digests))); + + teeEnforced.add(new DERTaggedObject(true, 10, new ASN1Integer(params.ecCurve))); + teeEnforced.add(new DERTaggedObject(true, 503, DERNull.INSTANCE)); + teeEnforced.add(new DERTaggedObject(true, 702, new ASN1Integer(0))); + teeEnforced.add(new DERTaggedObject(true, 704, rootOfTrust)); + teeEnforced.add(new DERTaggedObject(true, 705, new ASN1Integer(AttestationUtils.getOsVersion()))); + teeEnforced.add(new DERTaggedObject(true, 706, new ASN1Integer(AttestationUtils.getPatchLevel(false)))); + teeEnforced.add(new DERTaggedObject(true, 718, new ASN1Integer(AttestationUtils.getVendorPatchLevel(true)))); + teeEnforced.add(new DERTaggedObject(true, 719, new ASN1Integer(AttestationUtils.getBootPatchLevel(true)))); + + if (params.brand != null) { + teeEnforced.add(new DERTaggedObject(true, 710, new DEROctetString(params.brand))); + } + if (params.device != null) { + teeEnforced.add(new DERTaggedObject(true, 711, new DEROctetString(params.device))); + } + if (params.product != null) { + teeEnforced.add(new DERTaggedObject(true, 712, new DEROctetString(params.product))); + } + if (params.manufacturer != null) { + teeEnforced.add(new DERTaggedObject(true, 716, new DEROctetString(params.manufacturer))); + } + if (params.model != null) { + teeEnforced.add(new DERTaggedObject(true, 717, new DEROctetString(params.model))); + } + + ASN1EncodableVector softwareEnforced = new ASN1EncodableVector(); + try { + ASN1OctetString applicationId = createApplicationId(uid); + softwareEnforced.add(new DERTaggedObject(true, 709, applicationId)); + } catch (Throwable e) { + Log.w(TAG, "Failed to create application ID", e); + } + softwareEnforced.add(new DERTaggedObject(true, 701, new ASN1Integer(System.currentTimeMillis()))); + + ASN1Encodable[] keyDescriptionElements = new ASN1Encodable[] { + new ASN1Integer(AttestationUtils.getAttestVersion()), + new ASN1Enumerated(securityLevel), + new ASN1Integer(AttestationUtils.getKeymasterVersion()), + new ASN1Enumerated(securityLevel), + new DEROctetString(params.attestationChallenge != null ? params.attestationChallenge : new byte[0]), + new DEROctetString(new byte[0]), + new DERSequence(softwareEnforced), + new DERSequence(teeEnforced) + }; + + DERSequence keyDescription = new DERSequence(keyDescriptionElements); + DEROctetString keyDescriptionOctets = new DEROctetString(keyDescription.getEncoded()); + + return new Extension(ATTESTATION_OID, false, keyDescriptionOctets); + } catch (Exception e) { + Log.e(TAG, "Failed to build attestation extension", e); + throw new RuntimeException(e); + } + } + + private static Signature[] extractSignatures(PackageInfo info) { + SigningInfo signingInfo = info.signingInfo; + if (signingInfo != null) { + if (signingInfo.hasMultipleSigners()) { + return signingInfo.getApkContentsSigners(); + } + return signingInfo.getSigningCertificateHistory(); + } + return info.signatures; + } + + private static DEROctetString createApplicationId(int uid) throws Throwable { + Context context = ActivityThread.currentApplication(); + if (context == null) { + throw new IllegalStateException("createApplicationId: context not available from ActivityThread!"); + } + + PackageManager pm = context.getPackageManager(); + if (pm == null) { + throw new IllegalStateException("createApplicationId: PackageManager not found!"); + } + + String[] packages = pm.getPackagesForUid(uid); + if (packages == null || packages.length == 0) { + throw new IllegalStateException("No packages found for UID: " + uid); + } + + int size = packages.length; + ASN1Encodable[] packageInfoAA = new ASN1Encodable[size]; + Set signatures = new HashSet<>(); + MessageDigest dg = MessageDigest.getInstance("SHA-256"); + + for (int i = 0; i < size; i++) { + String name = packages[i]; + PackageInfo info = pm.getPackageInfo(name, PackageManager.GET_SIGNING_CERTIFICATES); + ASN1Encodable[] arr = new ASN1Encodable[2]; + arr[0] = new DEROctetString(name.getBytes(StandardCharsets.UTF_8)); + arr[1] = new ASN1Integer(info.getLongVersionCode()); + packageInfoAA[i] = new DERSequence(arr); + + Signature[] pkgSigs = extractSignatures(info); + if (pkgSigs != null) { + for (Signature s : pkgSigs) { + signatures.add(ByteBuffer.wrap(dg.digest(s.toByteArray()))); + } + } + } + + ASN1Encodable[] signaturesAA = new ASN1Encodable[signatures.size()]; + int i = 0; + for (ByteBuffer d : signatures) { + signaturesAA[i++] = new DEROctetString(d.array()); + } + + ASN1Encodable[] applicationIdAA = new ASN1Encodable[2]; + applicationIdAA[0] = new DERSet(packageInfoAA); + applicationIdAA[1] = new DERSet(signaturesAA); + + return new DEROctetString(new DERSequence(applicationIdAA).getEncoded()); + } +} diff --git a/core/java/android/security/trickystore/CertificateHacker.java b/core/java/android/security/trickystore/CertificateHacker.java new file mode 100644 index 0000000000000..fcd9a38b22e38 --- /dev/null +++ b/core/java/android/security/trickystore/CertificateHacker.java @@ -0,0 +1,311 @@ +package android.security.trickystore; + +import android.util.Log; + +import com.android.internal.org.bouncycastle.asn1.ASN1Boolean; +import com.android.internal.org.bouncycastle.asn1.ASN1Encodable; +import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector; +import com.android.internal.org.bouncycastle.asn1.ASN1Enumerated; +import com.android.internal.org.bouncycastle.asn1.ASN1Integer; +import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.internal.org.bouncycastle.asn1.ASN1Sequence; +import com.android.internal.org.bouncycastle.asn1.ASN1TaggedObject; +import com.android.internal.org.bouncycastle.asn1.DEROctetString; +import com.android.internal.org.bouncycastle.asn1.DERSequence; +import com.android.internal.org.bouncycastle.asn1.DERTaggedObject; +import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.android.internal.org.bouncycastle.asn1.x509.Extension; +import com.android.internal.org.bouncycastle.cert.X509CertificateHolder; +import com.android.internal.org.bouncycastle.cert.X509v3CertificateBuilder; +import com.android.internal.org.bouncycastle.crypto.digests.SHA256Digest; +import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters; +import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.android.internal.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.android.internal.org.bouncycastle.crypto.signers.ECDSASigner; +import com.android.internal.org.bouncycastle.crypto.signers.RSADigestSigner; +import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import com.android.internal.org.bouncycastle.jce.ECNamedCurveTable; +import com.android.internal.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import com.android.internal.org.bouncycastle.jce.spec.ECParameterSpec; +import com.android.internal.org.bouncycastle.operator.ContentSigner; +import com.android.internal.org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @hide + */ +public final class CertificateHacker { + private static final String TAG = "CertificateHacker"; + + private static final Map sLeafAlgorithms = new ConcurrentHashMap<>(); + + private CertificateHacker() {} + + public static void clearLeafAlgorithms() { + sLeafAlgorithms.clear(); + } + + public static Certificate[] hackCertificateChain(Certificate[] chain) { + if (chain == null || chain.length == 0) { + return chain; + } + + try { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + X509Certificate leaf = (X509Certificate) certFactory.generateCertificate( + new ByteArrayInputStream(chain[0].getEncoded())); + + byte[] extensionBytes = leaf.getExtensionValue( + CertificateGenerator.ATTESTATION_OID.getId()); + if (extensionBytes == null) { + return chain; + } + + X509CertificateHolder leafHolder = new X509CertificateHolder(leaf.getEncoded()); + Extension extension = leafHolder.getExtension(CertificateGenerator.ATTESTATION_OID); + ASN1Sequence sequence = ASN1Sequence.getInstance(extension.getExtnValue().getOctets()); + ASN1Encodable[] encodables = sequence.toArray(); + ASN1Sequence teeEnforced = (ASN1Sequence) encodables[7]; + + ASN1EncodableVector vector = new ASN1EncodableVector(); + ASN1Encodable originalRootOfTrust = null; + + for (ASN1Encodable element : teeEnforced) { + ASN1TaggedObject taggedObject = (ASN1TaggedObject) element; + if (taggedObject.getTagNo() == 704) { + originalRootOfTrust = taggedObject.getBaseObject().toASN1Primitive(); + } else { + vector.add(taggedObject); + } + } + + String algorithm = leaf.getPublicKey().getAlgorithm(); + KeyBoxManager keyboxManager = TrickyStoreService.getInstance().getKeyBoxManager(); + KeyBoxManager.KeyBox keybox = keyboxManager.getKeybox(algorithm); + + if (keybox == null) { + Log.e(TAG, "No keybox for algorithm: " + algorithm); + return chain; + } + + List certificates = new ArrayList<>(keybox.certificates); + X509CertificateHolder issuerHolder = new X509CertificateHolder( + certificates.get(0).getEncoded()); + + X509v3CertificateBuilder builder = new X509v3CertificateBuilder( + issuerHolder.getSubject(), + leafHolder.getSerialNumber(), + leafHolder.getNotBefore(), + leafHolder.getNotAfter(), + leafHolder.getSubject(), + leafHolder.getSubjectPublicKeyInfo() + ); + + ContentSigner signer = createBCSigner(leaf.getSigAlgName(), keybox.keyPair.getPrivate()); + + Extension hackedExtension = hackAttestExtension(originalRootOfTrust, vector, encodables); + builder.addExtension(hackedExtension); + + for (Object oid : leafHolder.getExtensions().getExtensionOIDs()) { + String oidString = oid.toString(); + if (!oidString.equals(CertificateGenerator.ATTESTATION_OID.getId())) { + builder.addExtension(leafHolder.getExtension( + new ASN1ObjectIdentifier(oidString))); + } + } + + X509CertificateHolder builtHolder = builder.build(signer); + X509Certificate hackedLeaf = (X509Certificate) certFactory.generateCertificate( + new ByteArrayInputStream(builtHolder.getEncoded())); + + List result = new ArrayList<>(); + result.add(hackedLeaf); + result.addAll(certificates); + return result.toArray(new Certificate[0]); + } catch (Exception e) { + Log.e(TAG, "Failed to hack certificate chain", e); + return chain; + } + } + + private static ContentSigner createBCSigner(String algorithm, PrivateKey privateKey) throws Exception { + AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(algorithm); + + if (privateKey instanceof BCECPrivateKey) { + BCECPrivateKey bcKey = (BCECPrivateKey) privateKey; + ECParameterSpec ecSpec = bcKey.getParameters(); + if (ecSpec != null) { + ECDomainParameters domainParams = new ECDomainParameters( + ecSpec.getCurve(), ecSpec.getG(), ecSpec.getN(), ecSpec.getH()); + ECPrivateKeyParameters keyParam = new ECPrivateKeyParameters(bcKey.getD(), domainParams); + return new ECContentSigner(sigAlgId, keyParam); + } else { + ECNamedCurveParameterSpec namedSpec = ECNamedCurveTable.getParameterSpec("secp256r1"); + ECDomainParameters domainParams = new ECDomainParameters( + namedSpec.getCurve(), namedSpec.getG(), namedSpec.getN(), namedSpec.getH()); + ECPrivateKeyParameters keyParam = new ECPrivateKeyParameters(bcKey.getD(), domainParams); + return new ECContentSigner(sigAlgId, keyParam); + } + } else if (privateKey instanceof ECPrivateKey) { + ECPrivateKeyParameters keyParam = (ECPrivateKeyParameters) ECUtil.generatePrivateKeyParameter(privateKey); + return new ECContentSigner(sigAlgId, keyParam); + } else if (privateKey instanceof RSAPrivateCrtKey) { + RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) privateKey; + RSAKeyParameters keyParam = new RSAKeyParameters(true, rsaKey.getModulus(), rsaKey.getPrivateExponent()); + return new RSAContentSigner(sigAlgId, keyParam); + } + + throw new IllegalArgumentException("Unsupported key type: " + privateKey.getClass()); + } + + private static class ECContentSigner implements ContentSigner { + private final AlgorithmIdentifier algId; + private final ECPrivateKeyParameters keyParam; + private final ByteArrayOutputStream stream; + + ECContentSigner(AlgorithmIdentifier algId, ECPrivateKeyParameters keyParam) { + this.algId = algId; + this.keyParam = keyParam; + this.stream = new ByteArrayOutputStream(); + } + + @Override + public AlgorithmIdentifier getAlgorithmIdentifier() { + return algId; + } + + @Override + public OutputStream getOutputStream() { + return stream; + } + + @Override + public byte[] getSignature() { + try { + byte[] data = stream.toByteArray(); + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(data); + + ECDSASigner signer = new ECDSASigner(); + signer.init(true, keyParam); + BigInteger[] sig = signer.generateSignature(hash); + + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(new ASN1Integer(sig[0])); + v.add(new ASN1Integer(sig[1])); + return new DERSequence(v).getEncoded(); + } catch (Exception e) { + throw new RuntimeException("Failed to generate ECDSA signature", e); + } + } + } + + private static class RSAContentSigner implements ContentSigner { + private final AlgorithmIdentifier algId; + private final RSAKeyParameters keyParam; + private final ByteArrayOutputStream stream; + + RSAContentSigner(AlgorithmIdentifier algId, RSAKeyParameters keyParam) { + this.algId = algId; + this.keyParam = keyParam; + this.stream = new ByteArrayOutputStream(); + } + + @Override + public AlgorithmIdentifier getAlgorithmIdentifier() { + return algId; + } + + @Override + public OutputStream getOutputStream() { + return stream; + } + + @Override + public byte[] getSignature() { + try { + byte[] data = stream.toByteArray(); + RSADigestSigner signer = new RSADigestSigner(new SHA256Digest()); + signer.init(true, keyParam); + signer.update(data, 0, data.length); + return signer.generateSignature(); + } catch (Exception e) { + throw new RuntimeException("Failed to generate RSA signature", e); + } + } + } + + private static Extension hackAttestExtension( + ASN1Encodable originalRootOfTrust, + ASN1EncodableVector vector, + ASN1Encodable[] originalEncodables) throws Exception { + + byte[] bootKey = AttestationUtils.getBootKey(); + byte[] bootHash = AttestationUtils.getBootHash(); + + if (bootHash == null && originalRootOfTrust instanceof ASN1Sequence) { + try { + ASN1Sequence rot = (ASN1Sequence) originalRootOfTrust; + ASN1Encodable hashElement = rot.getObjectAt(3); + if (hashElement instanceof DEROctetString) { + bootHash = ((DEROctetString) hashElement).getOctets(); + } + } catch (Exception e) { + Log.w(TAG, "Failed to extract boot hash from original", e); + } + } + + if (bootHash == null) { + bootHash = AttestationUtils.getBootHash(); + } + + ASN1Encodable[] rootOfTrustElements = new ASN1Encodable[] { + new DEROctetString(bootKey), + ASN1Boolean.TRUE, + new ASN1Enumerated(0), + new DEROctetString(bootHash) + }; + DERSequence hackedRootOfTrust = new DERSequence(rootOfTrustElements); + + vector.add(new DERTaggedObject(true, 718, + new ASN1Integer(AttestationUtils.getVendorPatchLevel(true)))); + vector.add(new DERTaggedObject(true, 719, + new ASN1Integer(AttestationUtils.getBootPatchLevel(true)))); + vector.add(new DERTaggedObject(true, 706, + new ASN1Integer(AttestationUtils.getPatchLevel(false)))); + vector.add(new DERTaggedObject(true, 705, + new ASN1Integer(AttestationUtils.getOsVersion()))); + vector.add(new DERTaggedObject(704, hackedRootOfTrust)); + + DERSequence hackedEnforced = new DERSequence(vector); + originalEncodables[7] = hackedEnforced; + DERSequence hackedSequence = new DERSequence(originalEncodables); + DEROctetString hackedOctets = new DEROctetString(hackedSequence); + + return new Extension(CertificateGenerator.ATTESTATION_OID, false, hackedOctets); + } + + public static void storeLeafAlgorithm(String alias, int uid, String algorithm) { + sLeafAlgorithms.put(alias + "_" + uid, algorithm); + } + + public static String getLeafAlgorithm(String alias, int uid) { + return sLeafAlgorithms.remove(alias + "_" + uid); + } +} diff --git a/core/java/android/security/trickystore/KeyBoxManager.java b/core/java/android/security/trickystore/KeyBoxManager.java new file mode 100644 index 0000000000000..b0b3f247f07fd --- /dev/null +++ b/core/java/android/security/trickystore/KeyBoxManager.java @@ -0,0 +1,306 @@ +package android.security.trickystore; + +import android.util.Log; + +import com.android.internal.org.bouncycastle.asn1.ASN1InputStream; +import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.android.internal.org.bouncycastle.asn1.ASN1Primitive; +import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.android.internal.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.android.internal.org.bouncycastle.asn1.sec.ECPrivateKey; +import com.android.internal.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.android.internal.org.bouncycastle.asn1.x9.X9ECParameters; +import com.android.internal.org.bouncycastle.crypto.params.ECDomainParameters; +import com.android.internal.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.EC; +import com.android.internal.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserFactory; + +import java.io.ByteArrayInputStream; +import java.io.StringReader; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @hide + */ +public class KeyBoxManager { + private static final String TAG = "KeyBoxManager"; + + private final Map mKeyboxes = new ConcurrentHashMap<>(); + + private static final Pattern PEM_HEADER = Pattern.compile("-----BEGIN ([^-]+)-----"); + + /** @hide */ + public static class KeyBox { + public final KeyPair keyPair; + public final List certificates; + + public KeyBox(KeyPair keyPair, List certificates) { + this.keyPair = keyPair; + this.certificates = certificates; + } + } + + public void clear() { + mKeyboxes.clear(); + Log.i(TAG, "Keyboxes cleared"); + } + + public boolean hasKeyboxes() { + return !mKeyboxes.isEmpty(); + } + + public KeyBox getKeybox(String algorithm) { + return mKeyboxes.get(algorithm); + } + + public void parseKeybox(String xmlContent) { + mKeyboxes.clear(); + if (xmlContent == null || xmlContent.isEmpty()) { + return; + } + + try { + xmlContent = sanitizeXml(xmlContent); + XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); + XmlPullParser parser = factory.newPullParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); + parser.setInput(new StringReader(xmlContent)); + + int currentKeyIndex = -1; + String currentAlgorithm = null; + String privateKeyPem = null; + List certificatePems = new ArrayList<>(); + StringBuilder privateKeyBuilder = null; + StringBuilder certBuilder = null; + boolean inKey = false; + boolean inPrivateKey = false; + boolean inCertificateChain = false; + boolean inCertificate = false; + + int eventType = parser.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + + switch (eventType) { + case XmlPullParser.START_TAG: + if ("Key".equals(tagName)) { + inKey = true; + currentKeyIndex++; + currentAlgorithm = parser.getAttributeValue(null, "algorithm"); + privateKeyPem = null; + certificatePems.clear(); + privateKeyBuilder = null; + certBuilder = null; + } else if ("PrivateKey".equals(tagName) && inKey) { + inPrivateKey = true; + privateKeyBuilder = new StringBuilder(); + } else if ("CertificateChain".equals(tagName) && inKey) { + inCertificateChain = true; + } else if ("Certificate".equals(tagName) && inCertificateChain) { + inCertificate = true; + certBuilder = new StringBuilder(); + } + break; + + case XmlPullParser.TEXT: + String text = parser.getText(); + if (text != null) { + if (inPrivateKey && privateKeyBuilder != null) { + privateKeyBuilder.append(text); + } else if (inCertificate && certBuilder != null) { + certBuilder.append(text); + } + } + break; + + case XmlPullParser.END_TAG: + if ("PrivateKey".equals(tagName)) { + if (privateKeyBuilder != null) { + String pem = privateKeyBuilder.toString().trim(); + if (!pem.isEmpty()) { + privateKeyPem = pem; + } + privateKeyBuilder = null; + } + inPrivateKey = false; + } else if ("Certificate".equals(tagName)) { + if (certBuilder != null) { + String pem = certBuilder.toString().trim(); + if (!pem.isEmpty()) { + certificatePems.add(pem); + } + certBuilder = null; + } + inCertificate = false; + } else if ("CertificateChain".equals(tagName)) { + inCertificateChain = false; + } else if ("Key".equals(tagName)) { + inKey = false; + if (currentAlgorithm != null && privateKeyPem != null && !certificatePems.isEmpty()) { + processKeybox(currentAlgorithm, privateKeyPem, certificatePems); + } + } + break; + } + + eventType = parser.next(); + } + + Log.i(TAG, "Parsed " + mKeyboxes.size() + " keyboxes"); + } catch (Exception e) { + Log.e(TAG, "Failed to parse keybox XML", e); + } + } + + private void processKeybox(String algorithm, String privateKeyPem, List certificatePems) { + try { + String normalizedAlgorithm; + switch (algorithm.toLowerCase()) { + case "ec": + case "ecdsa": + normalizedAlgorithm = "EC"; + break; + case "rsa": + normalizedAlgorithm = "RSA"; + break; + default: + normalizedAlgorithm = algorithm; + } + + PrivateKey privateKey = parsePrivateKey(privateKeyPem, normalizedAlgorithm); + List certificates = new ArrayList<>(); + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + + for (String certPem : certificatePems) { + byte[] certBytes = parsePemContent(certPem); + Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(certBytes)); + certificates.add(cert); + } + + if (!certificates.isEmpty()) { + PublicKey publicKey = ((X509Certificate) certificates.get(0)).getPublicKey(); + KeyPair keyPair = new KeyPair(publicKey, privateKey); + mKeyboxes.put(normalizedAlgorithm, new KeyBox(keyPair, certificates)); + Log.i(TAG, "Added keybox for algorithm: " + normalizedAlgorithm); + } + } catch (Exception e) { + Log.e(TAG, "Failed to process keybox for algorithm: " + algorithm, e); + } + } + + private PrivateKey parsePrivateKey(String pem, String algorithm) throws Exception { + String pemType = detectPemType(pem); + byte[] keyBytes = parsePemContent(pem); + + if ("EC PRIVATE KEY".equals(pemType) + || ("EC".equals(algorithm) && pemType == null)) { + return parseEcPrivateKey(keyBytes, algorithm); + } + + if ("RSA PRIVATE KEY".equals(pemType) + || ("RSA".equals(algorithm) && pemType == null)) { + return parseRsaPrivateKey(keyBytes); + } + + if ("PRIVATE KEY".equals(pemType) || "ENCRYPTED PRIVATE KEY".equals(pemType)) { + PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(keyBytes); + if ("RSA".equals(algorithm)) { + return new KeyFactorySpi().generatePrivate(pkInfo); + } + if ("EC".equals(algorithm)) { + return new EC().generatePrivate(pkInfo); + } + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + return KeyFactory.getInstance(algorithm).generatePrivate(spec); + } + + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); + return KeyFactory.getInstance(algorithm).generatePrivate(spec); + } + + private PrivateKey parseEcPrivateKey(byte[] keyBytes, String algorithm) throws Exception { + try (ASN1InputStream asn1In = new ASN1InputStream(keyBytes)) { + ASN1Primitive asn1 = asn1In.readObject(); + try { + ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(asn1); + X9ECParameters ecParams = ECNamedCurveTable.getByOID( + (ASN1ObjectIdentifier) ecPrivateKey.getParameters()); + ECDomainParameters domainParams = new ECDomainParameters( + ecParams.getCurve(), ecParams.getG(), ecParams.getN(), ecParams.getH()); + ECPrivateKeyParameters privParams = new ECPrivateKeyParameters( + ecPrivateKey.getKey(), domainParams); + return new BCECPrivateKey(algorithm, privParams, null); + } catch (Exception e) { + PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(asn1); + return new EC().generatePrivate(pkInfo); + } + } + } + + private PrivateKey parseRsaPrivateKey(byte[] keyBytes) throws Exception { + try (ASN1InputStream asn1In = new ASN1InputStream(keyBytes)) { + ASN1Primitive asn1 = asn1In.readObject(); + try { + RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(asn1); + RSAPrivateCrtKeySpec rsaSpec = new RSAPrivateCrtKeySpec( + rsaPrivateKey.getModulus(), + rsaPrivateKey.getPublicExponent(), + rsaPrivateKey.getPrivateExponent(), + rsaPrivateKey.getPrime1(), + rsaPrivateKey.getPrime2(), + rsaPrivateKey.getExponent1(), + rsaPrivateKey.getExponent2(), + rsaPrivateKey.getCoefficient()); + return KeyFactory.getInstance("RSA").generatePrivate(rsaSpec); + } catch (Exception e) { + PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(asn1); + return new KeyFactorySpi().generatePrivate(pkInfo); + } + } + } + + private String detectPemType(String pem) { + if (pem == null) return null; + Matcher m = PEM_HEADER.matcher(pem); + return m.find() ? m.group(1).trim().toUpperCase() : null; + } + + private byte[] parsePemContent(String pem) { + String base64 = pem + .replaceAll("-----BEGIN [^-]+-----", "") + .replaceAll("-----END [^-]+-----", "") + .replaceAll("\\s", ""); + return Base64.getDecoder().decode(base64); + } + + private String sanitizeXml(String content) { + content = content.trim(); + String[] boms = {"\uFEFF", "\uFFFE", "\u0000\uFEFF"}; + for (String bom : boms) { + if (content.startsWith(bom)) { + content = content.substring(bom.length()); + } + } + content = content.replaceAll("(?s)", ""); + return content.trim(); + } +} diff --git a/core/java/android/security/trickystore/TrickyStoreService.java b/core/java/android/security/trickystore/TrickyStoreService.java new file mode 100644 index 0000000000000..fd9c3ebcf387a --- /dev/null +++ b/core/java/android/security/trickystore/TrickyStoreService.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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 android.security.trickystore; + +import android.app.ActivityManager; +import android.os.RemoteException; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.util.JsonReader; +import android.util.Log; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.spec.ECGenParameterSpec; +import java.util.Base64; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @hide + */ +public class TrickyStoreService { + private static final String TAG = "TrickyStoreService"; + + private static TrickyStoreService sInstance; + + private final Set mHackPackages = ConcurrentHashMap.newKeySet(); + private final Set mGeneratePackages = ConcurrentHashMap.newKeySet(); + private final Map mPackageModes = new ConcurrentHashMap<>(); + + private volatile Boolean mTeeBroken = null; + private volatile CustomPatchLevel mCustomPatchLevel = null; + private volatile String mLastKeyboxFingerprint = null; + + private final KeyBoxManager mKeyBoxManager; + + /** @hide */ + public enum Mode { + AUTO, LEAF_HACK, GENERATE + } + + /** @hide */ + public static class CustomPatchLevel { + public final String system; + public final String vendor; + public final String boot; + public final String all; + + public CustomPatchLevel(String system, String vendor, String boot, String all) { + this.system = system; + this.vendor = vendor; + this.boot = boot; + this.all = all; + } + } + + private TrickyStoreService() { + mKeyBoxManager = new KeyBoxManager(); + } + + public static synchronized TrickyStoreService getInstance() { + if (sInstance == null) { + sInstance = new TrickyStoreService(); + sInstance.initialize(); + } + return sInstance; + } + + public void initialize() { + refreshTargets(); + refreshKeyBox(); + refreshPatchLevel(); + Log.i(TAG, "TrickyStoreService initialized"); + } + + private String fetchFromAms(Fetcher fetcher) { + try { + return fetcher.fetch(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to fetch trickystore config from system_server", e); + return null; + } + } + + private interface Fetcher { + String fetch() throws RemoteException; + } + + public void refreshTargets() { + String content = fetchFromAms(() -> ActivityManager.getService().getSpoofTrickyStoreTarget()); + mHackPackages.clear(); + mGeneratePackages.clear(); + mPackageModes.clear(); + + if (content == null || content.isEmpty()) { + return; + } + + String trimmed = content.trim(); + try { + if (trimmed.startsWith("[") || trimmed.startsWith("{")) { + parseTargetsJson(trimmed); + } else { + parseTargetsText(trimmed); + } + Log.i(TAG, "Updated target packages: hack=" + mHackPackages + + ", generate=" + mGeneratePackages + ", modes=" + mPackageModes); + } catch (Exception e) { + Log.e(TAG, "Failed to parse target packages", e); + } + } + + private void parseTargetsText(String content) { + for (String raw : content.split("\n")) { + String line = raw.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + + if (line.endsWith("!")) { + String pkg = line.substring(0, line.length() - 1).trim(); + mGeneratePackages.add(pkg); + mPackageModes.put(pkg, Mode.GENERATE); + } else if (line.endsWith("?")) { + String pkg = line.substring(0, line.length() - 1).trim(); + mHackPackages.add(pkg); + mPackageModes.put(pkg, Mode.LEAF_HACK); + } else { + mPackageModes.put(line, Mode.AUTO); + } + } + } + + private void parseTargetsJson(String content) throws IOException { + try (JsonReader reader = new JsonReader(new StringReader(content))) { + reader.beginArray(); + while (reader.hasNext()) { + reader.beginObject(); + String pkg = null; + String modeStr = "AUTO"; + while (reader.hasNext()) { + String key = reader.nextName(); + if ("package".equals(key)) { + pkg = reader.nextString(); + } else if ("mode".equals(key)) { + modeStr = reader.nextString(); + } else { + reader.skipValue(); + } + } + reader.endObject(); + if (pkg == null) continue; + Mode mode; + try { + mode = Mode.valueOf(modeStr.toUpperCase()); + } catch (IllegalArgumentException e) { + mode = Mode.AUTO; + } + mPackageModes.put(pkg, mode); + if (mode == Mode.LEAF_HACK) mHackPackages.add(pkg); + if (mode == Mode.GENERATE) mGeneratePackages.add(pkg); + } + reader.endArray(); + } + } + + public void refreshKeyBox() { + String raw = fetchFromAms(() -> ActivityManager.getService().getSpoofTrickyStoreKeyBox()); + if (raw == null || raw.isEmpty()) { + mKeyBoxManager.clear(); + mLastKeyboxFingerprint = null; + return; + } + String fingerprint = Integer.toHexString(raw.hashCode()) + ":" + raw.length(); + if (fingerprint.equals(mLastKeyboxFingerprint)) { + return; + } + String xml = decodeKeybox(raw); + if (xml == null) { + Log.e(TAG, "Keybox payload not recognised as XML or base64-encoded XML"); + return; + } + try { + mKeyBoxManager.parseKeybox(xml); + if (mKeyBoxManager.hasKeyboxes()) { + mLastKeyboxFingerprint = fingerprint; + Log.i(TAG, "Keybox updated successfully"); + } else { + mLastKeyboxFingerprint = null; + Log.e(TAG, "Keybox parse produced no usable entries"); + } + } catch (Exception e) { + mLastKeyboxFingerprint = null; + Log.e(TAG, "Failed to update keybox", e); + } + } + + private String decodeKeybox(String payload) { + String trimmed = payload.trim(); + if (trimmed.startsWith("<")) { + return trimmed; + } + try { + byte[] decoded = Base64.getDecoder().decode(trimmed); + String asXml = new String(decoded, StandardCharsets.UTF_8).trim(); + if (asXml.startsWith("<")) { + return asXml; + } + } catch (IllegalArgumentException ignored) { + } + return null; + } + + public void refreshPatchLevel() { + String content = fetchFromAms(() -> ActivityManager.getService().getSpoofTrickyStorePatch()); + if (content == null || content.isEmpty()) { + mCustomPatchLevel = null; + return; + } + + try { + String trimmed = content.trim(); + if (trimmed.startsWith("{")) { + parsePatchJson(trimmed); + } else { + parsePatchText(trimmed); + } + } catch (Exception e) { + Log.e(TAG, "Failed to parse patch level", e); + } + } + + private void parsePatchText(String content) { + StringBuilder filtered = new StringBuilder(); + for (String raw : content.split("\n")) { + String line = raw.trim(); + if (!line.isEmpty() && !line.startsWith("#")) { + filtered.append(line).append("\n"); + } + } + + String lines = filtered.toString().trim(); + if (lines.isEmpty()) { + mCustomPatchLevel = null; + return; + } + + String[] parts = lines.split("\n"); + if (parts.length == 1 && !parts[0].contains("=")) { + mCustomPatchLevel = new CustomPatchLevel(parts[0], parts[0], parts[0], parts[0]); + return; + } + + String system = null, vendor = null, boot = null, all = null; + for (String part : parts) { + int idx = part.indexOf('='); + if (idx > 0) { + String key = part.substring(0, idx).trim().toLowerCase(); + String value = part.substring(idx + 1).trim(); + switch (key) { + case "system": system = value; break; + case "vendor": vendor = value; break; + case "boot": boot = value; break; + case "all": all = value; break; + } + } + } + mCustomPatchLevel = new CustomPatchLevel( + system != null ? system : all, + vendor != null ? vendor : all, + boot != null ? boot : all, + all + ); + } + + private void parsePatchJson(String content) throws IOException { + String system = null, vendor = null, boot = null, all = null; + try (JsonReader reader = new JsonReader(new StringReader(content))) { + reader.beginObject(); + while (reader.hasNext()) { + String key = reader.nextName(); + switch (key) { + case "system": system = reader.nextString(); break; + case "vendor": vendor = reader.nextString(); break; + case "boot": boot = reader.nextString(); break; + case "all": all = reader.nextString(); break; + default: reader.skipValue(); break; + } + } + reader.endObject(); + } + mCustomPatchLevel = new CustomPatchLevel( + system != null ? system : all, + vendor != null ? vendor : all, + boot != null ? boot : all, + all + ); + } + + private void ensureTeeStatus() { + if (mTeeBroken == null) { + synchronized (this) { + if (mTeeBroken == null) { + mTeeBroken = checkTeeBroken(); + if (mTeeBroken) { + AttestationUtils.setTeeBroken(true); + } + } + } + } + } + + private boolean checkTeeBroken() { + try { + String alias = "TrickyStoreTeeCheck"; + KeyPairGenerator kpg = KeyPairGenerator.getInstance( + KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore"); + KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( + alias, KeyProperties.PURPOSE_SIGN) + .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1")) + .setDigests(KeyProperties.DIGEST_SHA256) + .setAttestationChallenge(new byte[16]); + + kpg.initialize(builder.build()); + kpg.generateKeyPair(); + + KeyStore ks = KeyStore.getInstance("AndroidKeyStore"); + ks.load(null); + ks.deleteEntry(alias); + + Log.i(TAG, "TEE verification successful"); + return false; + } catch (Exception e) { + Log.w(TAG, "TEE verification failed, TEE is broken", e); + return true; + } + } + + public boolean needHack(int callingUid, String[] packages) { + if (packages == null) return false; + refreshTargets(); + ensureTeeStatus(); + for (String pkg : packages) { + Mode mode = mPackageModes.get(pkg); + if (mode == Mode.LEAF_HACK) return true; + if (mode == Mode.AUTO && !mTeeBroken) return true; + } + return false; + } + + public boolean needGenerate(int callingUid, String[] packages) { + if (packages == null) return false; + refreshTargets(); + ensureTeeStatus(); + for (String pkg : packages) { + Mode mode = mPackageModes.get(pkg); + if (mode == Mode.GENERATE) return true; + if (mode == Mode.AUTO && mTeeBroken) return true; + } + return false; + } + + public KeyBoxManager getKeyBoxManager() { + refreshKeyBox(); + return mKeyBoxManager; + } + + public CustomPatchLevel getCustomPatchLevel() { + refreshPatchLevel(); + return mCustomPatchLevel; + } + + public boolean hasKeyboxes() { + return mKeyBoxManager.hasKeyboxes(); + } +} diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 417b478e9f410..3d909e02a29fa 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -526,7 +526,7 @@ private static boolean sameCondition(ZenRule rule) { } private static int[] generateMinuteBuckets() { - final int maxHrs = 12; + final int maxHrs = 24; final int[] buckets = new int[maxHrs + 3]; buckets[0] = 15; buckets[1] = 30; diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java index a8aea7c1eb599..3859418de2174 100644 --- a/core/java/android/speech/tts/TtsEngines.java +++ b/core/java/android/speech/tts/TtsEngines.java @@ -498,7 +498,7 @@ static public String[] toOldLocaleStringFormat(Locale locale) { * specific preference in the list. */ private static String parseEnginePrefFromList(String prefValue, String engineName) { - if (TextUtils.isEmpty(prefValue)) { + if (TextUtils.isEmpty(prefValue) || TextUtils.isEmpty(engineName)) { return null; } @@ -507,7 +507,7 @@ private static String parseEnginePrefFromList(String prefValue, String engineNam for (String value : prefValues) { final int delimiter = value.indexOf(':'); if (delimiter > 0) { - if (engineName.equals(value.substring(0, delimiter))) { + if ((value.substring(0, delimiter)).equals(engineName)) { return value.substring(delimiter + 1); } } @@ -560,7 +560,7 @@ private String updateValueInCommaSeparatedList(String list, String key, for (String value : prefValues) { final int delimiter = value.indexOf(':'); if (delimiter > 0) { - if (key.equals(value.substring(0, delimiter))) { + if (value.substring(0, delimiter).equals(key)) { if (first) { first = false; } else { diff --git a/core/java/android/util/DisplayUtils.java b/core/java/android/util/DisplayUtils.java index cbb38a4ada31a..91562c5d3f5d9 100644 --- a/core/java/android/util/DisplayUtils.java +++ b/core/java/android/util/DisplayUtils.java @@ -16,8 +16,10 @@ package android.util; +import android.content.Context; import android.content.res.Resources; import android.view.Display; +import android.view.DisplayInfo; import com.android.internal.R; @@ -83,4 +85,20 @@ public static float getPhysicalPixelDisplaySizeRatio( final float heightRatio = (float) currentHeight / physicalHeight; return Math.min(widthRatio, heightRatio); } + + /** + * Get the display size ratio for the current resolution vs the maximum supported + * resolution. + */ + public static float getScaleFactor(Context context) { + DisplayInfo displayInfo = new DisplayInfo(); + context.getDisplay().getDisplayInfo(displayInfo); + final Display.Mode maxDisplayMode = + getMaximumResolutionDisplayMode(displayInfo.supportedModes); + final float scaleFactor = getPhysicalPixelDisplaySizeRatio( + maxDisplayMode.getPhysicalWidth(), maxDisplayMode.getPhysicalHeight(), + displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight()); + + return scaleFactor; + } } diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java index 0dec1fabda0a6..a48c336f7b643 100644 --- a/core/java/android/util/EventLog.java +++ b/core/java/android/util/EventLog.java @@ -334,8 +334,6 @@ public int hashCode() { } } - // We assume that the native methods deal with any concurrency issues. - /** * Record an event log message. * @param tag The event type tag code @@ -343,7 +341,13 @@ public int hashCode() { * @return The number of bytes written */ @RavenwoodRedirect - public static native int writeEvent(int tag, int value); + public static int writeEvent(int tag, int value) { + if (!Build.IS_ENG) { + return 0; + } + + return nativeWriteEvent(tag, value); + } /** * Record an event log message. @@ -352,7 +356,13 @@ public int hashCode() { * @return The number of bytes written */ @RavenwoodRedirect - public static native int writeEvent(int tag, long value); + public static int writeEvent(int tag, long value) { + if (!Build.IS_ENG) { + return 0; + } + + return nativeWriteEvent(tag, value); + } /** * Record an event log message. @@ -361,7 +371,13 @@ public int hashCode() { * @return The number of bytes written */ @RavenwoodRedirect - public static native int writeEvent(int tag, float value); + public static int writeEvent(int tag, float value) { + if (!Build.IS_ENG) { + return 0; + } + + return nativeWriteEvent(tag, value); + } /** * Record an event log message. @@ -370,7 +386,13 @@ public int hashCode() { * @return The number of bytes written */ @RavenwoodRedirect - public static native int writeEvent(int tag, String str); + public static int writeEvent(int tag, String str) { + if (!Build.IS_ENG) { + return 0; + } + + return nativeWriteEvent(tag, str); + } /** * Record an event log message. @@ -379,7 +401,13 @@ public int hashCode() { * @return The number of bytes written */ @RavenwoodRedirect - public static native int writeEvent(int tag, Object... list); + public static int writeEvent(int tag, Object... list) { + if (!Build.IS_ENG) { + return 0; + } + + return nativeWriteEvent(tag, list); + } /** * Read events from the log, filtered by type. @@ -388,8 +416,14 @@ public int hashCode() { * @throws IOException if something goes wrong reading events */ @RavenwoodThrow - public static native void readEvents(int[] tags, Collection output) - throws IOException; + public static void readEvents(int[] tags, Collection output) + throws IOException { + if (!Build.IS_ENG) { + return; + } + + nativeReadEvents(tags, output); + } /** * Read events from the log, filtered by type, blocking until logs are about to be overwritten. @@ -401,7 +435,27 @@ public static native void readEvents(int[] tags, Collection output) */ @SystemApi @RavenwoodThrow - public static native void readEventsOnWrapping(int[] tags, long timestamp, + public static void readEventsOnWrapping(int[] tags, long timestamp, + Collection output) + throws IOException { + if (!Build.IS_ENG) { + return; + } + + nativeReadEventsOnWrapping(tags, timestamp, output); + } + + // We assume that the native methods deal with any concurrency issues. + + private static native int nativeWriteEvent(int tag, int value); + private static native int nativeWriteEvent(int tag, long value); + private static native int nativeWriteEvent(int tag, float value); + private static native int nativeWriteEvent(int tag, String str); + private static native int nativeWriteEvent(int tag, Object... list); + + private static native void nativeReadEvents(int[] tags, Collection output) + throws IOException; + private static native void nativeReadEventsOnWrapping(int[] tags, long timestamp, Collection output) throws IOException; diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index c1ed19fef032b..4f8a1e3a7803b 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -178,8 +178,7 @@ private PackageUtils() { * device, otherwise a byte array of size {@link #HIGH_RAM_BUFFER_SIZE_BYTES} */ public static @NonNull byte[] createLargeFileBuffer() { - int bufferSize = ActivityManager.isLowRamDeviceStatic() - ? LOW_RAM_BUFFER_SIZE_BYTES : HIGH_RAM_BUFFER_SIZE_BYTES; + int bufferSize = LOW_RAM_BUFFER_SIZE_BYTES; return new byte[bufferSize]; } diff --git a/core/java/android/util/RecurrenceRule.java b/core/java/android/util/RecurrenceRule.java index 9ef9c723ca278..fc373ee9c9ce4 100644 --- a/core/java/android/util/RecurrenceRule.java +++ b/core/java/android/util/RecurrenceRule.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.net.ProtocolException; import java.time.Clock; +import java.time.DayOfWeek; import java.time.LocalTime; import java.time.Period; import java.time.ZoneId; @@ -80,6 +81,26 @@ public static RecurrenceRule buildRecurringMonthly(int dayOfMonth, ZoneId zone) return new RecurrenceRule(start, null, Period.ofMonths(1)); } + @UnsupportedAppUsage + public static RecurrenceRule buildRecurringWeekly(int dayOfWeek, ZoneId zone) { + final ZonedDateTime now = ZonedDateTime.now(sClock).withZoneSameInstant(zone); + final DayOfWeek dayNow = now.getDayOfWeek(); + final DayOfWeek dayStart = DayOfWeek.of(dayOfWeek); + final int minusDays = dayNow.getValue() - dayStart.getValue(); + final ZonedDateTime start = ZonedDateTime.of( + now.toLocalDate().minusWeeks(1).minusDays(minusDays), + LocalTime.MIDNIGHT, zone); + return new RecurrenceRule(start, null, Period.ofWeeks(1)); + } + + @UnsupportedAppUsage + public static RecurrenceRule buildRecurringDaily(int hourOfDay, ZoneId zone) { + final ZonedDateTime now = ZonedDateTime.now(sClock).withZoneSameInstant(zone); + final ZonedDateTime start = ZonedDateTime.of(now.toLocalDate(), + LocalTime.MIDNIGHT.plusHours(hourOfDay), zone); + return new RecurrenceRule(start, null, Period.ofDays(1)); + } + private RecurrenceRule(Parcel source) { start = convertZonedDateTime(source.readString()); end = convertZonedDateTime(source.readString()); @@ -168,6 +189,24 @@ public boolean isMonthly() { && period.getDays() == 0; } + @UnsupportedAppUsage + public boolean isWeekly() { + return start != null + && period != null + && period.getYears() == 0 + && period.getMonths() == 0 + && period.getDays() == 7; + } + + @UnsupportedAppUsage + public boolean isDaily() { + return start != null + && period != null + && period.getYears() == 0 + && period.getMonths() == 0 + && period.getDays() == 1; + } + public Iterator> cycleIterator() { if (period != null) { return new RecurringIterator(); diff --git a/core/java/android/util/TimingsTraceLog.java b/core/java/android/util/TimingsTraceLog.java index b4f4729c82b27..9c3a02a5d3ead 100644 --- a/core/java/android/util/TimingsTraceLog.java +++ b/core/java/android/util/TimingsTraceLog.java @@ -37,7 +37,7 @@ @android.ravenwood.annotation.RavenwoodKeepWholeClass public class TimingsTraceLog { // Debug boot time for every step if it's non-user build. - private static final boolean DEBUG_BOOT_TIME = !Build.IS_USER; + private static final boolean DEBUG_BOOT_TIME = false; // Maximum number of nested calls that are stored private static final int MAX_NESTED_CALLS = 10; diff --git a/core/java/android/util/proto/ProtoFieldFilter.java b/core/java/android/util/proto/ProtoFieldFilter.java index c3ae106b68f81..3a0e674ab9b68 100644 --- a/core/java/android/util/proto/ProtoFieldFilter.java +++ b/core/java/android/util/proto/ProtoFieldFilter.java @@ -307,7 +307,7 @@ private void skipBytes(InputStream in, long n) throws IOException { while (bytesRemaining > 0) { int bytesToRead = (int) Math.min(bytesRemaining, mBuffer.length); int bytesRead = in.read(mBuffer, 0, bytesToRead); - if (bytesRemaining < 0) { + if (bytesRead < 0) { throw new IOException("EOF while skipping bytes"); } bytesRemaining -= bytesRead; diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 37782ac7f2f23..0352f4417b63a 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -226,6 +226,7 @@ public String toString() { private long mFrameIntervalNanos; private long mLastFrameIntervalNanos; + private boolean mEnableTraversalLast; private boolean mDebugPrintNextFrameTimeDelta; private int mFPSDivisor = 1; private final DisplayEventReceiver.VsyncEventData mLastVsyncEventData = @@ -301,7 +302,8 @@ public void onWaitForBufferRelease(long durationNanos) { * @hide */ private static final String[] CALLBACK_TRACE_TITLES = { - "input", "animation", "insets_animation", "traversal", "commit" + "input", "animation", "insets_animation", "traversal", "commit", + "traversal_last" }; /** @@ -352,7 +354,9 @@ public void onWaitForBufferRelease(long durationNanos) { */ public static final int CALLBACK_COMMIT = 4; - private static final int CALLBACK_LAST = CALLBACK_COMMIT; + /** @hide */ + public static final int CALLBACK_TRAVERSAL_LAST = 5; + private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL_LAST; private Choreographer(Looper looper, int vsyncSource) { this(looper, vsyncSource, /* layerHandle */ 0L); @@ -400,6 +404,14 @@ public static Choreographer getInstance() { return sThreadInstance.get(); } + /** @hide */ + public void setEnableTraversalLast(boolean enable) { + mEnableTraversalLast = enable; + } + /** @hide */ + public boolean isEnableTraversalLast() { + return mEnableTraversalLast; + } /** * @hide * @deprecated Use vsync IDs with the regular Choreographer instead. @@ -1163,6 +1175,9 @@ void doFrame(long frameTimeNanos, int frame, mFrameInfo.markPerformTraversalsStart(); doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameIntervalNanos); + if (mEnableTraversalLast) { + doCallbacks(Choreographer.CALLBACK_TRAVERSAL_LAST, frameIntervalNanos); + } doCallbacks(Choreographer.CALLBACK_COMMIT, frameIntervalNanos); } finally { AnimationUtils.unlockAnimationClock(); diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index e3d2ad5282014..3960099bc82cb 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -355,6 +355,14 @@ public final class InputDevice implements Parcelable { */ public static final int SOURCE_SENSOR = 0x04000000 | SOURCE_CLASS_NONE; + /** + * The input source is a specific virtual event sent from navigation bar. + * + * @see com.android.systemui.navigationbar.buttons.KeyButtonView#sendEvent() + * @hide + */ + public static final int SOURCE_NAVIGATION_BAR = 0x06000000 | SOURCE_CLASS_BUTTON; + /** * A special input source constant that is used when filtering input devices * to match devices that provide any type of input source. diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java index 746139ce695eb..4d14f841c47fb 100644 --- a/core/java/android/view/InputEventReceiver.java +++ b/core/java/android/view/InputEventReceiver.java @@ -227,7 +227,13 @@ public final void finishInputEvent(InputEvent event, boolean handled) { } else { int seq = mSeqMap.valueAt(index); mSeqMap.removeAt(index); - nativeFinishInputEvent(mReceiverPtr, seq, handled); + try { + nativeFinishInputEvent(mReceiverPtr, seq, handled); + } catch (RuntimeException e) { + // Just log the exception instead of crashing + Log.w(TAG, "Exception in nativeFinishInputEvent: " + e.getMessage()); + return; + } } } event.recycleIfNeededAfterDispatch(); diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 3317ae60ec9b3..7d93ce08d32c3 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -1259,13 +1259,16 @@ public void hide(@InsetsType int types) { public void hide(@InsetsType int types, @Nullable ImeTracker.Token statsToken) { if ((types & ime()) != 0) { - ProtoLog.d(IME_INSETS_CONTROLLER, "hide(ime())"); - - if (statsToken == null) { - statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, - ImeTracker.ORIGIN_CLIENT, - SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, - mHost.isHandlingPointerEvent() /* fromUser */); + if ((mRequestedVisibleTypes & ime()) != 0 + || getAnimationType(ime()) == ANIMATION_TYPE_USER) { + ProtoLog.d(IME_INSETS_CONTROLLER, "hide(ime())"); + + if (statsToken == null) { + statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE, + ImeTracker.ORIGIN_CLIENT, + SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, + mHost.isHandlingPointerEvent() /* fromUser */); + } } } Trace.asyncTraceBegin(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index f91ef7416a85b..b42961ffc08b9 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -39,6 +39,7 @@ import android.widget.FrameLayout; import com.android.internal.R; +import com.android.internal.util.ViewCacheManager; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -457,6 +458,35 @@ public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean a + Integer.toHexString(resource) + ")"); } + ViewCacheManager cache = ViewCacheManager.getInstance(); + cache.recordLayoutRes(resource); + if (cache.isEnable()) { + View cached = cache.tryGet(resource); + if (cached != null) { + if (root != null) { + try { + XmlResourceParser parser = res.getLayout(resource); + try { + AttributeSet attrs = Xml.asAttributeSet(parser); + advanceToRootNode(parser); + ViewGroup.LayoutParams params = root.generateLayoutParams(attrs); + if (!attachToRoot) { + cached.setLayoutParams(params); + return cached; + } + root.addView(cached, params); + return root; + } finally { + parser.close(); + } + } catch (Exception e) { + } + } else { + return cached; + } + } + } + XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); @@ -689,67 +719,75 @@ public final View createView(@NonNull Context viewContext, @NonNull String name, throws ClassNotFoundException, InflateException { Objects.requireNonNull(viewContext); Objects.requireNonNull(name); - Constructor constructor = sConstructorMap.get(name); - if (constructor != null && !verifyClassLoader(constructor)) { - constructor = null; - sConstructorMap.remove(name); - } + String prefixedName = prefix != null ? (prefix + name) : name; Class clazz = null; try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, name); - if (constructor == null) { - // Class not found in the cache, see if it's real, and try to add it - clazz = Class.forName(prefix != null ? (prefix + name) : name, false, - mContext.getClassLoader()).asSubclass(View.class); - - if (mFilter != null && clazz != null) { - boolean allowed = mFilter.onLoadClass(clazz); - if (!allowed) { - failNotAllowed(name, prefix, viewContext, attrs); - } + // Opportunistically create view directly instead of using reflection + View view = tryCreateViewDirect(prefixedName, viewContext, attrs); + if (view == null) { + Constructor constructor = sConstructorMap.get(name); + if (constructor != null && !verifyClassLoader(constructor)) { + constructor = null; + sConstructorMap.remove(name); } - constructor = clazz.getConstructor(mConstructorSignature); - constructor.setAccessible(true); - sConstructorMap.put(name, constructor); - } else { - // If we have a filter, apply it to cached constructor - if (mFilter != null) { - // Have we seen this name before? - Boolean allowedState = mFilterMap.get(name); - if (allowedState == null) { - // New class -- remember whether it is allowed - clazz = Class.forName(prefix != null ? (prefix + name) : name, false, - mContext.getClassLoader()).asSubclass(View.class); - - boolean allowed = clazz != null && mFilter.onLoadClass(clazz); - mFilterMap.put(name, allowed); + + if (constructor == null) { + // Class not found in the cache, see if it's real, and try to add it + clazz = Class.forName(prefixedName, false, + mContext.getClassLoader()).asSubclass(View.class); + + if (mFilter != null && clazz != null) { + boolean allowed = mFilter.onLoadClass(clazz); if (!allowed) { failNotAllowed(name, prefix, viewContext, attrs); } - } else if (allowedState.equals(Boolean.FALSE)) { - failNotAllowed(name, prefix, viewContext, attrs); + } + constructor = clazz.getConstructor(mConstructorSignature); + constructor.setAccessible(true); + sConstructorMap.put(name, constructor); + } else { + // If we have a filter, apply it to cached constructor + if (mFilter != null) { + // Have we seen this name before? + Boolean allowedState = mFilterMap.get(name); + if (allowedState == null) { + // New class -- remember whether it is allowed + clazz = Class.forName(prefixedName, false, + mContext.getClassLoader()).asSubclass(View.class); + + boolean allowed = clazz != null && mFilter.onLoadClass(clazz); + mFilterMap.put(name, allowed); + if (!allowed) { + failNotAllowed(name, prefix, viewContext, attrs); + } + } else if (allowedState.equals(Boolean.FALSE)) { + failNotAllowed(name, prefix, viewContext, attrs); + } } } - } - Object lastContext = mConstructorArgs[0]; - mConstructorArgs[0] = viewContext; - Object[] args = mConstructorArgs; - args[1] = attrs; + Object lastContext = mConstructorArgs[0]; + mConstructorArgs[0] = viewContext; + Object[] args = mConstructorArgs; + args[1] = attrs; - try { - final View view = constructor.newInstance(args); - if (view instanceof ViewStub) { - // Use the same context when inflating ViewStub later. - final ViewStub viewStub = (ViewStub) view; - viewStub.setLayoutInflater(cloneInContext((Context) args[0])); + try { + view = constructor.newInstance(args); + } finally { + mConstructorArgs[0] = lastContext; } - return view; - } finally { - mConstructorArgs[0] = lastContext; } + + if (view instanceof ViewStub) { + // Use the same context when inflating ViewStub later. + final ViewStub viewStub = (ViewStub) view; + viewStub.setLayoutInflater(cloneInContext((Context) viewContext)); + } + + return view; } catch (NoSuchMethodException e) { final InflateException ie = new InflateException( getParserStateDescription(viewContext, attrs) @@ -1244,4 +1282,121 @@ protected void dispatchDraw(Canvas canvas) { } } } + + // Some of the views included here are deprecated, but apps still use them. + @SuppressWarnings("deprecation") + private static View tryCreateViewDirect(String name, Context context, AttributeSet attributeSet) { + // This contains all the framework views used in a set of 113 real-world apps, sorted by + // number of occurrences. While views with only 1 occurrence are unlikely to be worth + // optimizing, it doesn't hurt to include them because switch-case is compiled into a table + // lookup after calling String#hashCode(). + switch (name) { + case "android.widget.LinearLayout": // 13486 occurrences + return new android.widget.LinearLayout(context, attributeSet); + case "android.widget.View": // 6930 occurrences + case "android.webkit.View": // 63 occurrences + case "android.view.View": // 63 occurrences + case "android.app.View": // 62 occurrences + return new android.view.View(context, attributeSet); + case "android.widget.FrameLayout": // 6447 occurrences + return new android.widget.FrameLayout(context, attributeSet); + case "android.widget.ViewStub": // 5613 occurrences + case "android.view.ViewStub": // 228 occurrences + case "android.app.ViewStub": // 227 occurrences + case "android.webkit.ViewStub": // 226 occurrences + return new android.view.ViewStub(context, attributeSet); + case "android.widget.TextView": // 4722 occurrences + return new android.widget.TextView(context, attributeSet); + case "android.widget.ImageView": // 3044 occurrences + return new android.widget.ImageView(context, attributeSet); + case "android.widget.RelativeLayout": // 2665 occurrences + return new android.widget.RelativeLayout(context, attributeSet); + case "android.widget.Space": // 1694 occurrences + return new android.widget.Space(context, attributeSet); + case "android.widget.ProgressBar": // 770 occurrences + return new android.widget.ProgressBar(context, attributeSet); + case "android.widget.Button": // 382 occurrences + return new android.widget.Button(context, attributeSet); + case "android.widget.ImageButton": // 265 occurrences + return new android.widget.ImageButton(context, attributeSet); + case "android.widget.Switch": // 145 occurrences + return new android.widget.Switch(context, attributeSet); + case "android.widget.DateTimeView": // 117 occurrences + return new android.widget.DateTimeView(context, attributeSet); + case "android.widget.Toolbar": // 86 occurrences + return new android.widget.Toolbar(context, attributeSet); + case "android.widget.HorizontalScrollView": // 68 occurrences + return new android.widget.HorizontalScrollView(context, attributeSet); + case "android.widget.ScrollView": // 67 occurrences + return new android.widget.ScrollView(context, attributeSet); + case "android.widget.NotificationHeaderView": // 65 occurrences + case "android.webkit.NotificationHeaderView": // 65 occurrences + case "android.view.NotificationHeaderView": // 65 occurrences + case "android.app.NotificationHeaderView": // 65 occurrences + return new android.view.NotificationHeaderView(context, attributeSet); + case "android.widget.ListView": // 58 occurrences + return new android.widget.ListView(context, attributeSet); + case "android.widget.QuickContactBadge": // 50 occurrences + return new android.widget.QuickContactBadge(context, attributeSet); + case "android.widget.SeekBar": // 40 occurrences + return new android.widget.SeekBar(context, attributeSet); + case "android.widget.CheckBox": // 38 occurrences + return new android.widget.CheckBox(context, attributeSet); + case "android.widget.GridLayout": // 16 occurrences + return new android.widget.GridLayout(context, attributeSet); + case "android.widget.TableRow": // 15 occurrences + return new android.widget.TableRow(context, attributeSet); + case "android.widget.RadioGroup": // 15 occurrences + return new android.widget.RadioGroup(context, attributeSet); + case "android.widget.Chronometer": // 15 occurrences + return new android.widget.Chronometer(context, attributeSet); + case "android.widget.ViewFlipper": // 13 occurrences + return new android.widget.ViewFlipper(context, attributeSet); + case "android.widget.Spinner": // 9 occurrences + return new android.widget.Spinner(context, attributeSet); + case "android.widget.ViewSwitcher": // 8 occurrences + return new android.widget.ViewSwitcher(context, attributeSet); + case "android.widget.TextSwitcher": // 8 occurrences + return new android.widget.TextSwitcher(context, attributeSet); + case "android.widget.SurfaceView": // 8 occurrences + case "android.webkit.SurfaceView": // 1 occurrence + case "android.view.SurfaceView": // 1 occurrence + case "android.app.SurfaceView": // 1 occurrence + return new android.view.SurfaceView(context, attributeSet); + case "android.widget.CheckedTextView": // 8 occurrences + return new android.widget.CheckedTextView(context, attributeSet); + case "android.preference.PreferenceFrameLayout": // 8 occurrences + return new android.preference.PreferenceFrameLayout(context, attributeSet); + case "android.widget.TwoLineListItem": // 7 occurrences + return new android.widget.TwoLineListItem(context, attributeSet); + case "android.widget.TableLayout": // 5 occurrences + return new android.widget.TableLayout(context, attributeSet); + case "android.widget.EditText": // 5 occurrences + return new android.widget.EditText(context, attributeSet); + case "android.widget.TabWidget": // 3 occurrences + return new android.widget.TabWidget(context, attributeSet); + case "android.widget.TabHost": // 3 occurrences + return new android.widget.TabHost(context, attributeSet); + case "android.widget.ZoomButton": // 2 occurrences + return new android.widget.ZoomButton(context, attributeSet); + case "android.widget.TextureView": // 2 occurrences + case "android.webkit.TextureView": // 2 occurrences + case "android.app.TextureView": // 2 occurrences + case "android.view.TextureView": // 2 occurrences + return new android.view.TextureView(context, attributeSet); + case "android.widget.ExpandableListView": // 2 occurrences + return new android.widget.ExpandableListView(context, attributeSet); + case "android.widget.ViewAnimator": // 1 occurrence + return new android.widget.ViewAnimator(context, attributeSet); + case "android.widget.TextClock": // 1 occurrence + return new android.widget.TextClock(context, attributeSet); + case "android.widget.AutoCompleteTextView": // 1 occurrence + return new android.widget.AutoCompleteTextView(context, attributeSet); + case "android.widget.WebView": // 1 occurrence + case "android.webkit.WebView": // 1 occurrence + return new android.webkit.WebView(context, attributeSet); + } + + return null; + } } diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java index c26506eafe998..3242716bd8b9c 100644 --- a/core/java/android/view/SurfaceControlViewHost.java +++ b/core/java/android/view/SurfaceControlViewHost.java @@ -511,8 +511,10 @@ public void setView(@NonNull View view, @NonNull WindowManager.LayoutParams attr attrs.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; addWindowToken(attrs); view.setLayoutParams(attrs); - mViewRoot.setView(view, attrs, null); - mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent); + if (mViewRoot.mDisplay != null) { + mViewRoot.setView(view, attrs, null); + mViewRoot.setBackKeyCallbackForWindowlessWindow(mWm::forwardBackKeyToParent); + } } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 49a7da2d88ed8..c3da50d5a1493 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -52,6 +52,7 @@ import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; +import android.provider.Settings; import android.text.TextUtils; import android.util.ArraySet; import android.util.AttributeSet; @@ -953,7 +954,9 @@ public boolean setZOrderedOnTop(boolean onTop, boolean allowDynamicChange) { * @param isSecure True if the surface view is secure. */ public void setSecure(boolean isSecure) { - if (isSecure) { + boolean ignoreSecure = Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.WINDOW_IGNORE_SECURE, 0) == 1; + if (isSecure && !ignoreSecure) { mSurfaceFlags |= SurfaceControl.SECURE; } else { mSurfaceFlags &= ~SurfaceControl.SECURE; diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index c3f4071aa82ea..7c87a40fd5a4a 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -158,6 +158,18 @@ public final class ThreadedRenderer extends HardwareRenderer { */ public static final String OVERDRAW_PROPERTY_SHOW = "show"; + /** + * Defines the rendering pipeline to be used by the ThreadedRenderer. + * + * Possible values: + * "opengl", will use the existing OpenGL renderer + * "skiagl", will use Skia's OpenGL renderer + * "skiavk", will use Skia's Vulkan renderer + * + * @hide + */ + public static final String DEBUG_RENDERER_PROPERTY = "debug.hwui.renderer"; + /** * Turn on to debug non-rectangular clip operations. * diff --git a/core/java/android/view/ViewBackgroundThread.java b/core/java/android/view/ViewBackgroundThread.java new file mode 100644 index 0000000000000..bf7a0ae303e3e --- /dev/null +++ b/core/java/android/view/ViewBackgroundThread.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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 android.view; + +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Process; + +import java.util.concurrent.Executor; + +/** + * @hide + */ +public final class ViewBackgroundThread extends HandlerThread { + private static final long SLOW_DELIVERY_THRESHOLD_MS = 30000; + private static final long SLOW_DISPATCH_THRESHOLD_MS = 10000; + private static volatile Handler sHandler; + private static HandlerExecutor sHandlerExecutor; + private static volatile ViewBackgroundThread sInstance; + + private ViewBackgroundThread() { + super("view.bg", Process.THREAD_PRIORITY_BACKGROUND); + } + + private static void ensureThreadLocked() { + if (sInstance == null) { + sInstance = new ViewBackgroundThread(); + sInstance.start(); + } + if (sHandler == null) { + Looper looper = sInstance.getLooper(); + looper.setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, + SLOW_DELIVERY_THRESHOLD_MS); + sHandler = new Handler(sInstance.getLooper()); + sHandlerExecutor = new HandlerExecutor(sHandler); + } + } + + public static void init() { + synchronized (ViewBackgroundThread.class) { + if (sInstance == null) { + sInstance = new ViewBackgroundThread(); + sInstance.start(); + } + } + } + + public static ViewBackgroundThread get() { + synchronized (ViewBackgroundThread.class) { + ensureThreadLocked(); + return sInstance; + } + } + + public static Handler getHandler() { + synchronized (ViewBackgroundThread.class) { + ensureThreadLocked(); + return sHandler; + } + } + + public static Executor getExecutor() { + synchronized (ViewBackgroundThread.class) { + ensureThreadLocked(); + return sHandlerExecutor; + } + } +} diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index f070d87ef354c..afd7abfd7fe4f 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -267,7 +267,7 @@ public class ViewConfiguration { * The coefficient of friction applied to flings/scrolls. */ @UnsupportedAppUsage - private static final float SCROLL_FRICTION = 0.015f; + private static final float SCROLL_FRICTION = 0.012f; /** * Max distance in dips to overscroll for edge effects diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index fa1c190eb4e2b..e47bc28382956 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -297,6 +297,7 @@ import com.android.internal.policy.PhoneFallbackEventHandler; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.ViewCacheManager; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.SurfaceCallbackHelper; @@ -642,6 +643,7 @@ default void onConfigurationChanged(@NonNull Configuration overrideConfig, private boolean mPendingDragResizing; private boolean mDragResizing; private boolean mInvalidateRootRequested; + private boolean mFirstFrameDrawn = true; private int mCanvasOffsetX; private int mCanvasOffsetY; CompatibilityInfo.Translator mTranslator; @@ -723,6 +725,9 @@ default void onConfigurationChanged(@NonNull Configuration overrideConfig, public boolean mTraversalScheduled; int mTraversalBarrier; boolean mWillDrawSoon; + private boolean mIsNeedDrawLast = false; + private boolean mResident = false; + private boolean mHideByCache = false; /** Set to true while in performTraversals for detecting when die(true) is called from internal * callbacks such as onMeasure, onPreDraw, onDraw and deferring doDie() until later. */ boolean mIsInTraversal; @@ -816,7 +821,6 @@ public static final class NoPreloadHolder { */ private Transaction mPendingTransaction = new Transaction(); - boolean mIsDrawing; int mLastSystemUiVisibility; int mClientWindowLayoutFlags; @@ -1074,7 +1078,6 @@ public HandwritingInitiator getHandwritingInitiator() { */ private SurfaceSyncGroup mActiveSurfaceSyncGroup; - private final Object mPreviousSyncSafeguardLock = new Object(); /** @@ -1266,7 +1269,12 @@ public void onCornerRadiiChanged(float[] cornerRadii) { private static boolean sToolkitEnableInvalidateCheckThreadFlagValue = Flags.enableInvalidateCheckThread(); - private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true); + // Disable VRR feature to meet power expectations. + // VRR wakes up the idle device after 750ms timeout. This bounds Display and GPU to + // wake up as well, leading to higher power consumption during idling. + // Disable VRR to avoid this extra wakeup call as it can cause power regression. + // Google bug: https://partnerissuetracker.corp.google.com/u/0/issues/409971466 + private static final boolean sEnableVrr = false; private static final boolean sToolkitInitialTouchBoostFlagValue = toolkitInitialTouchBoost(); private static boolean sToolkitFrameRateDebugFlagValue = toolkitFrameRateDebug(); @@ -1553,8 +1561,12 @@ public void setView(View view, WindowManager.LayoutParams attrs, View panelParen attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/); } - CompatibilityInfo compatibilityInfo = - mDisplay.getDisplayAdjustments().getCompatibilityInfo(); + CompatibilityInfo compatibilityInfo; + if (mDisplay != null) { + compatibilityInfo = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); + } else { + compatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; + } mTranslator = compatibilityInfo.getTranslator(); // If the application owns the surface, don't enable hardware acceleration @@ -1708,9 +1720,13 @@ && hasSystemApplicationOverlayAppOp()) { + mWindow + " -- another window of type " + mWindowAttributes.type + " already exists"); case WindowManagerGlobal.ADD_PERMISSION_DENIED: - throw new WindowManager.BadTokenException("Unable to add window " - + mWindow + " -- permission denied for window type " - + mWindowAttributes.type); + if (com.android.internal.util.matrixx.PixelPropsUtils.shouldBypassTaskPermission(Binder.getCallingUid())) { + return; + } else { + throw new WindowManager.BadTokenException("Unable to add window " + + mWindow + " -- permission denied for window type " + + mWindowAttributes.type); + } case WindowManagerGlobal.ADD_INVALID_DISPLAY: throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified display can not be found"); @@ -1818,7 +1834,6 @@ private void registerListeners() { mAccessibilityManager.addHighContrastTextStateChangeListener( mExecutor, mHighContrastTextManager); - long eventsToBeRegistered = (mIsSubscribeGranularDisplayEventsEnabled) ? DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED @@ -2368,6 +2383,20 @@ private void handleResized(ClientWindowFrames frames, boolean reportDraw, return; } + if (reportDraw && forceLayout && seqId > mSyncSeqId) { + final boolean noSizeChange = !frameChanged && !attachedFrameChanged + && !dragResizingChanged && !compatScaleChanged; + final boolean noConfigOrDisplayChange = !configChanged && !displayChanged; + if (noSizeChange && noConfigOrDisplayChange + && mBasePackageName != null + && mBasePackageName.startsWith("com.android.launcher")) { + mSyncSeqId = seqId; + mLastSyncSeqId = mSyncSeqId; + reportNextDraw("resized"); + requestLayout(); + return; + } + } mPendingDragResizing = dragResizing; mTmpFrames.compatScale = compatScale; mInvCompatScale = 1f / compatScale; @@ -2769,7 +2798,6 @@ void setWindowStopped(boolean stopped) { logColorMode(mCurrentColorMode, true); } - /** Register callbacks to be notified when the ViewRootImpl surface changes. */ public interface SurfaceChangedCallback { void surfaceCreated(Transaction t); @@ -3104,8 +3132,13 @@ void scheduleTraversals() { // the scheduled traversals have occurred unless the message is // specifically "asynchronous" - see Message#setAsynchronous mTraversalBarrier = mQueue.postSyncBarrier(); - mChoreographer.postCallback( - Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); + if (mIsNeedDrawLast && mChoreographer.isEnableTraversalLast()) { + mChoreographer.postCallback( + Choreographer.CALLBACK_TRAVERSAL_LAST, mTraversalRunnable, null); + } else { + mChoreographer.postCallback( + Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); + } notifyRendererOfFramePending(); pokeDrawLockIfNeeded(); } @@ -3115,8 +3148,13 @@ void unscheduleTraversals() { if (mTraversalScheduled) { mTraversalScheduled = false; mQueue.removeSyncBarrier(mTraversalBarrier); - mChoreographer.removeCallbacks( - Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); + if (mIsNeedDrawLast && mChoreographer.isEnableTraversalLast()) { + mChoreographer.removeCallbacks( + Choreographer.CALLBACK_TRAVERSAL_LAST, mTraversalRunnable, null); + } else { + mChoreographer.removeCallbacks( + Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); + } } } @@ -3125,9 +3163,54 @@ void doTraversal() { mTraversalScheduled = false; mQueue.removeSyncBarrier(mTraversalBarrier); performTraversals(); + if (mFirstFrameDrawn) { + ViewCacheManager.getInstance().onTraversalEnd(this); + mFirstFrameDrawn = false; + } } } + public void setIsNeedDrawLast(boolean isNeed) { + mIsNeedDrawLast = isNeed; + } + public boolean isNeedDrawLast() { + return mIsNeedDrawLast; + } + public void setResident(boolean resident) { + mResident = resident; + } + public boolean isResident() { + return mResident; + } + public boolean setHideByCache(boolean hideByCache) { + if (!mResident) { + return false; + } + if (hideByCache && mView != null && mView.getContext() instanceof android.app.Activity + && ((android.app.Activity) mView.getContext()).isFinishing()) { + return false; + } + if (mHideByCache == hideByCache) { + return hideByCache; + } + mHideByCache = hideByCache; + final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; + if (!hideByCache) { + mForceNextWindowRelayout = true; + mReportNextDraw = true; + mLastReportNextDrawReason = "rebuiltByCache"; + scheduleTraversals(); + } else if (renderer != null) { + renderer.setStopped(true); + } + if (!hideByCache && renderer != null) { + renderer.allocateBuffers(); + } + return hideByCache; + } + public boolean isHideByCache() { + return mHideByCache; + } private void applyKeepScreenOnFlag(WindowManager.LayoutParams params) { // Update window's global keep screen on flag: if a view has requested // that the screen be kept on, then it is always set; otherwise, it is @@ -6760,7 +6843,9 @@ private void performConfigurationChange(@NonNull MergedConfiguration mergedConfi + ", globalConfig: " + globalConfig + ", overrideConfig: " + overrideConfig); - final CompatibilityInfo ci = mDisplay.getDisplayAdjustments().getCompatibilityInfo(); + final CompatibilityInfo ci = mDisplay != null + ? mDisplay.getDisplayAdjustments().getCompatibilityInfo() + : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO; if (!ci.equals(CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO)) { globalConfig = new Configuration(globalConfig); overrideConfig = new Configuration(overrideConfig); @@ -8011,6 +8096,11 @@ private int processMotionEvent(QueuedInputEvent q) { private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; + if (event.getPointerCount() == 3 && isThreeFingersSwipeActive()) { + event.setAction(MotionEvent.ACTION_CANCEL); + Log.d(mTag, "canceling motionEvent because of threeGesture detecting"); + } + // Translate the pointer event for compatibility, if needed. if (mTranslator != null) { mTranslator.translateEventInScreenToAppWindow(event); @@ -8472,7 +8562,6 @@ public boolean isHandlingPointerEvent() { return mAttachInfo.mHandlingPointerEvent; } - /** * If there is pointer that is showing a PointerIcon in this window, refresh the icon for that * pointer. This will resolve the PointerIcon through the view hierarchy. @@ -11296,7 +11385,6 @@ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent even } } break; - case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED: { handleWindowContentChangedEvent(event); } break; @@ -13265,7 +13353,6 @@ public void setChildBoundingInsets(@NonNull Rect insets) { scheduleTraversals(); } - private void logAndTrace(String msg) { if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.instant(Trace.TRACE_TAG_VIEW, mTag + "-" + msg); @@ -13314,7 +13401,6 @@ private void setCategoryFromCategoryCounts() { mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT; } - if (mFrameRateCategoryHighCount > 0) { mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; } else if (mFrameRateCategoryHighHintCount > 0) { @@ -13824,4 +13910,13 @@ private void preInitBufferAllocator() { public Choreographer getChoreographer() { return mChoreographer; } + + private boolean isThreeFingersSwipeActive() { + try { + return ActivityManager.getService().isThreeFingersSwipeActive(); + } catch (RemoteException e) { + Log.e(mTag, "isThreeFingersSwipeActive exception", e); + return false; + } + } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index e849926e9375e..fc2c33b439ec5 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.HIDE_OVERLAY_WINDOWS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import android.annotation.ColorInt; @@ -52,6 +53,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.provider.Settings; import android.transition.Scene; import android.transition.Transition; import android.transition.TransitionManager; @@ -1364,6 +1366,10 @@ public void clearFlags(int flags) { * @see #clearFlags */ public void setFlags(int flags, int mask) { + if ((mask & FLAG_SECURE) != 0 && Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.WINDOW_IGNORE_SECURE, 0) == 1) { + mask &= ~FLAG_SECURE; + } final WindowManager.LayoutParams attrs = getAttributes(); attrs.flags = (attrs.flags&~mask) | (flags&mask); mForcedWindowFlags |= mask; diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index a64e9fa56993b..e563d1781b45a 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -40,6 +40,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; +import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.ArraySet; @@ -480,6 +481,14 @@ public void addView(View view, ViewGroup.LayoutParams params, windowlessSession, new WindowlessWindowLayout()); } + boolean ignoreSecure = Settings.Global.getInt( + view.getContext().getContentResolver(), + Settings.Global.WINDOW_IGNORE_SECURE, 0) == 1; + + if (ignoreSecure) { + wparams.flags &= ~WindowManager.LayoutParams.FLAG_SECURE; + } + view.setLayoutParams(wparams); mViews.add(view); @@ -510,6 +519,14 @@ public void updateViewLayout(View view, ViewGroup.LayoutParams params) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } + boolean ignoreSecure = Settings.Global.getInt( + view.getContext().getContentResolver(), + Settings.Global.WINDOW_IGNORE_SECURE, 0) == 1; + + if (ignoreSecure) { + wparams.flags &= ~WindowManager.LayoutParams.FLAG_SECURE; + } + view.setLayoutParams(wparams); synchronized (mLock) { diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index dbb68372ab985..19463738dac82 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -30,13 +30,17 @@ import android.content.res.Resources.Theme; import android.content.res.XmlResourceParser; import android.os.SystemClock; +import android.os.SystemProperties; import android.ravenwood.annotation.RavenwoodIgnore; import android.ravenwood.annotation.RavenwoodKeepPartialClass; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.TimeUtils; import android.util.Xml; import android.view.InflateException; +import com.android.internal.R; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -56,6 +60,10 @@ public class AnimationUtils { */ private static final int TOGETHER = 0; private static final int SEQUENTIALLY = 1; + + /** @hide **/ + public static final boolean sPerfAnimEnabled = SystemProperties.getBoolean( + "persist.sys.activity_anim_perf_override", false); private static boolean sExpectedPresentationTimeFlagValue; static { @@ -109,9 +117,7 @@ public static void lockAnimationClock(long vsyncMillis, long expectedPresentatio AnimationState state = sAnimationState.get(); state.animationClockLocked = true; state.currentVsyncTimeMillis = vsyncMillis; - if (!sExpectedPresentationTimeFlagValue) { - state.mExpectedPresentationTimeNanos = expectedPresentationTimeNanos; - } + state.mExpectedPresentationTimeNanos = expectedPresentationTimeNanos; } /** @@ -158,7 +164,9 @@ public static void lockAnimationClock(long vsyncMillis) { @TestApi @RavenwoodIgnore public static void unlockAnimationClock() { - sAnimationState.get().animationClockLocked = false; + AnimationState state = sAnimationState.get(); + state.animationClockLocked = false; + state.mExpectedPresentationTimeNanos = 0L; } /** @@ -193,11 +201,13 @@ public static long currentAnimationTimeMillis() { @FlaggedApi(FLAG_EXPECTED_PRESENTATION_TIME_READ_ONLY) public static long getExpectedPresentationTimeNanos() { if (!sExpectedPresentationTimeFlagValue) { - return SystemClock.uptimeMillis() * TimeUtils.NANOS_PER_MS; + return System.nanoTime(); } AnimationState state = sAnimationState.get(); - return state.mExpectedPresentationTimeNanos; + return (state.mExpectedPresentationTimeNanos != 0L) + ? state.mExpectedPresentationTimeNanos + : System.nanoTime(); } /** @@ -224,6 +234,21 @@ public static long getExpectedPresentationTimeMillis() { public static Animation loadAnimation(Context context, @AnimRes int id) throws NotFoundException { + if (sPerfAnimEnabled) { + switch (id) { + case R.anim.activity_open_enter: + return ActivityAnimations.getOpenEnter(); + case R.anim.activity_open_exit: + return ActivityAnimations.getOpenExit(); + case R.anim.activity_close_enter: + return ActivityAnimations.getCloseEnter(); + case R.anim.activity_close_exit: + return ActivityAnimations.getCloseExit(); + case R.anim.app_starting_exit: + return ActivityAnimations.getAppStartingExit(); + } + } + XmlResourceParser parser = null; try { parser = context.getResources().getAnimation(id); @@ -504,4 +529,159 @@ private static Interpolator createInterpolatorFromXml( } return interpolator; } + + /** @hide */ + public final class ActivityAnimations { + + private static Animation sOpenEnter; + private static Animation sOpenExit; + private static Animation sCloseEnter; + private static Animation sCloseExit; + private static Animation sAppStartingExit; + + private static SpringInterpolator sSpatialSpec; + private static SpringInterpolator sEffectsSpec; + + private static final float DISTANCE = 0.333f; + private static final long APP_STARTING_EXIT_DURATION_MS = 150L; + + private ActivityAnimations() {} + + /** @hide */ + public static void preload() { + sSpatialSpec = new SpringInterpolator(0.8f, 380f); + sEffectsSpec = new SpringInterpolator(1.0f, 3800f); + sOpenEnter = new ActivityAnimFactory() + .fromX(1.0f) + .toX(0.0f) + .build(); + sOpenExit = new ActivityAnimFactory() + .fromX(0.0f) + .toX(-DISTANCE) + .build(); + sCloseEnter = new ActivityAnimFactory() + .fromX(-DISTANCE) + .toX(0.0f) + .build(); + sCloseExit = new ActivityAnimFactory() + .fromX(0.0f) + .toX(1.0f) + .build(); + sAppStartingExit = buildAppStartingExit(); + } + + private static Animation buildAppStartingExit() { + Animation animation = new AlphaAnimation(1.0f, 0.0f); + animation.setDuration(APP_STARTING_EXIT_DURATION_MS); + animation.setInterpolator(new LinearInterpolator()); + return animation; + } + + private static class ActivityAnimFactory { + private float fromX = 0f, toX = 0f; + + public ActivityAnimFactory fromX(float ratio) { + this.fromX = ratio; + return this; + } + + public ActivityAnimFactory toX(float ratio) { + this.toX = ratio; + return this; + } + + public Animation build() { + AnimationSet animationSet = new AnimationSet(false); + TranslateAnimation slide = new TranslateAnimation( + Animation.RELATIVE_TO_SELF, fromX, + Animation.RELATIVE_TO_SELF, toX, + Animation.RELATIVE_TO_SELF, 0f, + Animation.RELATIVE_TO_SELF, 0f + ); + slide.setDuration(sSpatialSpec.getDurationMs()); + slide.setInterpolator(sSpatialSpec); + animationSet.addAnimation(slide); + return animationSet; + } + } + + /** @hide */ + public static Animation getOpenEnter() { + return sOpenEnter; + } + + /** @hide */ + public static Animation getOpenExit() { + return sOpenExit; + } + + /** @hide */ + public static Animation getCloseEnter() { + return sCloseEnter; + } + + /** @hide */ + public static Animation getCloseExit() { + return sCloseExit; + } + + /** @hide */ + public static Animation getAppStartingExit() { + return sAppStartingExit; + } + } + + /** @hide */ + public static final class SpringInterpolator implements Interpolator { + private final float mDampingRatio; + private final float mOmega0; + private final long mDurationMs; + private final float mDurationSec; + private final float mEndOutput; + private final float mEndGap; + + public SpringInterpolator(float dampingRatio, float stiffness) { + mDampingRatio = dampingRatio; + mOmega0 = (float) Math.sqrt(stiffness); + final float settleSec; + if (dampingRatio >= 1.0f) { + settleSec = 9.23f / mOmega0; + } else { + settleSec = 6.91f / (dampingRatio * mOmega0); + } + mDurationMs = Math.max(50L, (long) (settleSec * 1000f)); + mDurationSec = mDurationMs / 1000f; + mEndOutput = rawSpring(mDurationSec); + mEndGap = 1.0f - mEndOutput; + } + + public long getDurationMs() { + return mDurationMs; + } + + private float rawSpring(float t) { + final float zeta = mDampingRatio; + final float w0 = mOmega0; + if (zeta < 1.0f) { + final float wd = w0 * (float) Math.sqrt(1.0f - zeta * zeta); + final float env = (float) Math.exp(-zeta * w0 * t); + return 1.0f - env * ((float) Math.cos(wd * t) + + (zeta * w0 / wd) * (float) Math.sin(wd * t)); + } else if (zeta > 1.0f) { + final float d = (float) Math.sqrt(zeta * zeta - 1.0f); + final float r1 = -w0 * (zeta - d); + final float r2 = -w0 * (zeta + d); + return 1.0f - (r2 * (float) Math.exp(r1 * t) + - r1 * (float) Math.exp(r2 * t)) / (r2 - r1); + } else { + final float env = (float) Math.exp(-w0 * t); + return 1.0f - env * (1.0f + w0 * t); + } + } + + @Override + public float getInterpolation(float input) { + return rawSpring(input * mDurationSec) + mEndGap * input; + } + } } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 61ade5fdad8b2..49c1c2f3535db 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -713,6 +713,7 @@ public abstract class AbsListView extends AdapterView implements Te private int mMinimumVelocity; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051740) private int mMaximumVelocity; + private int mDecacheThreshold; private float mVelocityScale = 1.0f; final boolean[] mIsScrap = new boolean[1]; @@ -1029,6 +1030,7 @@ private void initAbsListView() { mVerticalScrollFactor = configuration.getScaledVerticalScrollFactor(); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mDecacheThreshold = mMaximumVelocity / 2; mOverscrollDistance = configuration.getScaledOverscrollDistance(); mOverflingDistance = configuration.getScaledOverflingDistance(); @@ -4278,6 +4280,10 @@ private void onTouchUp(MotionEvent ev) { } mSelector.setHotspot(x, ev.getY()); } + if (!mDataChanged && !mIsDetaching + && isAttachedToWindow()) { + performClick.run(); + } if (mTouchModeReset != null) { removeCallbacks(mTouchModeReset); } @@ -4288,10 +4294,6 @@ public void run() { mTouchMode = TOUCH_MODE_REST; child.setPressed(false); setPressed(false); - if (!mDataChanged && !mIsDetaching - && isAttachedToWindow()) { - performClick.run(); - } } }; postDelayed(mTouchModeReset, @@ -4997,7 +4999,7 @@ public void run() { // Keep the fling alive a little longer postDelayed(this, FLYWHEEL_TIMEOUT); } else { - endFling(); + endFling(false); // Don't disable the scrolling cache right after it was enabled mTouchMode = TOUCH_MODE_SCROLL; reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL); } @@ -5017,6 +5019,11 @@ float getSplineFlingDistance(int velocity) { // Use AbsListView#fling(int) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void start(int initialVelocity) { + if (Math.abs(initialVelocity) > mDecacheThreshold) { + // For long flings, scrolling cache causes stutter, so don't use it + clearScrollingCache(); + } + int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0; mLastFlingY = initialY; mScroller.setInterpolator(null); @@ -5097,6 +5104,10 @@ void startScroll(int distance, int duration, boolean linear, // To interrupt a fling early you should use smoothScrollBy(0,0) instead @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) void endFling() { + endFling(true); + } + + void endFling(boolean clearCache) { mTouchMode = TOUCH_MODE_REST; removeCallbacks(this); @@ -5105,7 +5116,8 @@ void endFling() { if (!mSuppressIdleStateChangeCall) { reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE); } - clearScrollingCache(); + if (clearCache) + clearScrollingCache(); mScroller.abortAnimation(); if (mFlingStrictSpan != null) { diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index ca9cd66188aad..8eaebde4a40ea 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -165,10 +165,6 @@ void update() { if (mLocalTime == null || getVisibility() == GONE) { return; } - if (mShowRelativeTime) { - updateRelativeTime(); - return; - } int display; ZoneId zoneId = ZoneId.systemDefault(); @@ -476,6 +472,13 @@ void updateAll() { final int count = mAttachedViews.size(); for (int i = 0; i < count; i++) { DateTimeView view = mAttachedViews.get(i); + if (view.mShowRelativeTime) { + // Every minute, the status bar only needs to execute this function once + // to update the display + view.post(() -> view.updateRelativeTime()); + return; + } + view.post(() -> view.clearFormatAndUpdate()); } } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index c110ab9560303..9a7c1bf61cbd6 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -26,6 +26,7 @@ import android.compat.annotation.EnabledSince; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.graphics.BlendMode; import android.graphics.Canvas; @@ -35,6 +36,7 @@ import android.graphics.Rect; import android.graphics.RenderNode; import android.os.Build; +import android.provider.Settings; import android.util.AttributeSet; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; @@ -43,6 +45,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import com.android.internal.util.matrixx.VibrationUtils; + /** * This class performs the graphical effect used at the edges of scrollable widgets * when the user scrolls beyond the content bounds in 2D space. @@ -218,6 +222,10 @@ public class EdgeEffect { private float mDisplacement = 0.5f; private float mTargetDisplacement = 0.5f; + private boolean callerHasVibratePermission; + private int vibrateIntensity; + private Context mContext; + /** * Current edge effect type, consumers should always query * {@link #getCurrentEdgeEffectBehavior()} instead of this parameter @@ -233,6 +241,8 @@ public class EdgeEffect { */ public EdgeEffect(Context context) { this(context, null); + mContext = context; + updateCallerAndVibIntensity(); } /** @@ -241,6 +251,7 @@ public EdgeEffect(Context context) { * @param attrs The attributes of the XML tag that is inflating the view */ public EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) { + mContext = context; final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.EdgeEffect); final int themeColor = a.getColor( @@ -253,6 +264,14 @@ public EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) { mPaint.setColor((themeColor & 0xffffff) | 0x33000000); mPaint.setStyle(Paint.Style.FILL); mPaint.setBlendMode(DEFAULT_BLEND_MODE); + updateCallerAndVibIntensity(); + } + + private void updateCallerAndVibIntensity() { + callerHasVibratePermission = mContext.checkCallingOrSelfPermission( + android.Manifest.permission.VIBRATE) == PackageManager.PERMISSION_GRANTED; + vibrateIntensity = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.EDGE_SCROLLING_HAPTICS_INTENSITY, 1); } @EdgeEffectType @@ -497,6 +516,9 @@ public void onAbsorb(int velocity) { mState = STATE_RECEDE; mVelocity = velocity * ON_ABSORB_VELOCITY_ADJUSTMENT; mStartTime = AnimationUtils.currentAnimationTimeMillis(); + if (callerHasVibratePermission) { + VibrationUtils.triggerVibration(mContext, vibrateIntensity); + } } else if (edgeEffectBehavior == TYPE_GLOW) { mState = STATE_ABSORB; mVelocity = 0; @@ -521,6 +543,9 @@ public void onAbsorb(int velocity) { mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); mTargetDisplacement = 0.5f; + if (callerHasVibratePermission) { + VibrationUtils.triggerVibration(mContext, vibrateIntensity); + } } else { finish(); } diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 1ff8952b07729..fe3ab0f81859b 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -272,8 +272,8 @@ public ListView(Context context, AttributeSet attrs, int defStyleAttr, int defSt } } - mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, true); - mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, true); + mHeaderDividersEnabled = a.getBoolean(R.styleable.ListView_headerDividersEnabled, false); + mFooterDividersEnabled = a.getBoolean(R.styleable.ListView_footerDividersEnabled, false); a.recycle(); diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index d54addbbcb8d0..376707deaa721 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1531,6 +1531,7 @@ private PopupBackgroundView createBackgroundView(View contentView) { final PopupBackgroundView.LayoutParams listParams = new PopupBackgroundView.LayoutParams( MATCH_PARENT, height); backgroundView.addView(contentView, listParams); + backgroundView.setClipToOutline(true); return backgroundView; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0589afd1185e7..0dbbdc8d43e4b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -873,6 +873,7 @@ private void applyErrorDrawableIfNeeded(int layoutDirection) { // more bold. private int mFontWeightAdjustment; private Typeface mOriginalTypeface; + private String mFontFamily; // True if setKeyListener() has been explicitly called private boolean mListenerChanged = false; @@ -4388,6 +4389,7 @@ private void readTextAppearance(Context context, TypedArray appearance, attributes.mTypefaceIndex = appearance.getInt(attr, attributes.mTypefaceIndex); if (attributes.mTypefaceIndex != -1 && !attributes.mFontFamilyExplicit) { attributes.mFontFamily = null; + mFontFamily = null; } break; case com.android.internal.R.styleable.TextAppearance_fontFamily: @@ -4400,6 +4402,7 @@ private void readTextAppearance(Context context, TypedArray appearance, } if (attributes.mFontTypeface == null) { attributes.mFontFamily = appearance.getString(attr); + mFontFamily = attributes.mFontFamily; } attributes.mFontFamilyExplicit = true; break; @@ -4495,6 +4498,7 @@ private void applyTextAppearance(TextAppearanceAttributes attributes) { if (attributes.mTypefaceIndex != -1 && !attributes.mFontFamilyExplicit) { attributes.mFontFamily = null; + mFontFamily = null; } setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily, attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight); @@ -4528,6 +4532,10 @@ private void applyTextAppearance(TextAppearanceAttributes attributes) { setFontVariationSettings(attributes.mFontVariationSettings); } + if (Typeface.getFontName().equals("inter")) { + setFontFeatureSettings("'ss01'"); + } + if (attributes.mHasLineBreakStyle || attributes.mHasLineBreakWordStyle) { updateLineBreakConfigFromTextAppearance(attributes.mHasLineBreakStyle, attributes.mHasLineBreakWordStyle, attributes.mLineBreakStyle, @@ -4669,6 +4677,13 @@ protected void onConfigurationChanged(Configuration newConfig) { invalidate(); } } + + if (!TextUtils.equals(mFontFamily, Typeface.getFontName())) { + Typeface tf = Typeface.getOverrideTypeface(mFontFamily); + setTypeface(tf); + mFontFamily = Typeface.getFontName(); + } + if (mFontWeightAdjustment != newConfig.fontWeightAdjustment) { mFontWeightAdjustment = newConfig.fontWeightAdjustment; setTypeface(getTypeface()); diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java index 6963237fc19be..9a967b18d5117 100644 --- a/core/java/android/widget/ToastPresenter.java +++ b/core/java/android/widget/ToastPresenter.java @@ -22,8 +22,10 @@ import android.app.INotificationManager; import android.app.ITransientNotificationCallback; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.os.IBinder; @@ -68,6 +70,7 @@ public static View getTextToastView(Context context, CharSequence text) { View view = LayoutInflater.from(context).inflate(TEXT_TOAST_LAYOUT, null); TextView textView = view.findViewById(com.android.internal.R.id.message); textView.setText(text); + textView.setSelected(true); return view; } @@ -82,6 +85,7 @@ public static View getTextToastViewWithIcon(Context context, CharSequence text, View view = LayoutInflater.from(context).inflate(TEXT_TOAST_LAYOUT_WITH_ICON, null); TextView textView = view.findViewById(com.android.internal.R.id.message); textView.setText(text); + textView.setSelected(true); ImageView imageView = view.findViewById(com.android.internal.R.id.icon); if (imageView != null) { imageView.setImageDrawable(icon); @@ -251,6 +255,22 @@ public void show(View view, IBinder token, IBinder windowToken, int duration, in adjustLayoutParams(mParams, windowToken, duration, gravity, xOffset, yOffset, horizontalMargin, verticalMargin, removeWindowAnimations); + + ImageView appIcon = (ImageView) mView.findViewById(android.R.id.icon); + if (appIcon != null) { + Context context = mContext.get(); + if (context != null) { + PackageManager pm = context.getPackageManager(); + Drawable icon = null; + try { + icon = pm.getApplicationIcon(mPackageName); + } catch (PackageManager.NameNotFoundException e) { + // nothing to do + } + appIcon.setImageDrawable(icon); + } + } + addToastView(); trySendAccessibilityEvent(mView, mPackageName); if (callback != null) { diff --git a/core/java/android/window/WindowContext.java b/core/java/android/window/WindowContext.java index 806ad2172a5fe..685270f9f018b 100644 --- a/core/java/android/window/WindowContext.java +++ b/core/java/android/window/WindowContext.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; +import android.app.ActivityThread; import android.content.ComponentCallbacks; import android.content.ComponentCallbacksController; import android.content.Context; @@ -142,7 +143,7 @@ public Object getSystemService(String name) { @Override protected void finalize() throws Throwable { try { - release(); + getMainThreadHandler().post(this::release); } finally { super.finalize(); } diff --git a/core/java/com/android/internal/app/HiddenNotificationInfo.aidl b/core/java/com/android/internal/app/HiddenNotificationInfo.aidl new file mode 100644 index 0000000000000..7965bff3eb66c --- /dev/null +++ b/core/java/com/android/internal/app/HiddenNotificationInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2025-2026 AxionOS 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.internal.app; + +parcelable HiddenNotificationInfo; diff --git a/core/java/com/android/internal/app/HiddenNotificationInfo.java b/core/java/com/android/internal/app/HiddenNotificationInfo.java new file mode 100644 index 0000000000000..58a5afd0153e5 --- /dev/null +++ b/core/java/com/android/internal/app/HiddenNotificationInfo.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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.internal.app; + +import android.app.PendingIntent; +import android.graphics.drawable.Icon; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class HiddenNotificationInfo implements Parcelable { + public final String key; + public final String packageName; + public final Icon appIcon; + public final CharSequence title; + public final CharSequence text; + public final PendingIntent contentIntent; + public final long postTime; + public final int userId; + + public HiddenNotificationInfo( + String key, + String packageName, + Icon appIcon, + CharSequence title, + CharSequence text, + PendingIntent contentIntent, + long postTime, + int userId) { + this.key = key; + this.packageName = packageName; + this.appIcon = appIcon; + this.title = title; + this.text = text; + this.contentIntent = contentIntent; + this.postTime = postTime; + this.userId = userId; + } + + protected HiddenNotificationInfo(Parcel in) { + key = in.readString(); + packageName = in.readString(); + appIcon = in.readParcelable(Icon.class.getClassLoader(), Icon.class); + title = in.readCharSequence(); + text = in.readCharSequence(); + contentIntent = in.readParcelable(PendingIntent.class.getClassLoader(), PendingIntent.class); + postTime = in.readLong(); + userId = in.readInt(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(key); + dest.writeString(packageName); + dest.writeParcelable(appIcon, flags); + dest.writeCharSequence(title); + dest.writeCharSequence(text); + dest.writeParcelable(contentIntent, flags); + dest.writeLong(postTime); + dest.writeInt(userId); + } + + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public HiddenNotificationInfo createFromParcel(Parcel in) { + return new HiddenNotificationInfo(in); + } + + @Override + public HiddenNotificationInfo[] newArray(int size) { + return new HiddenNotificationInfo[size]; + } + }; +} diff --git a/core/java/com/android/internal/app/IAppLockStateListener.aidl b/core/java/com/android/internal/app/IAppLockStateListener.aidl new file mode 100644 index 0000000000000..3008571018a50 --- /dev/null +++ b/core/java/com/android/internal/app/IAppLockStateListener.aidl @@ -0,0 +1,8 @@ +package com.android.internal.app; + +/** + * @hide + */ +oneway interface IAppLockStateListener { + void onAppLockStateChanged(String packageName, boolean locked); +} diff --git a/core/java/com/android/internal/app/IAppSessionListener.aidl b/core/java/com/android/internal/app/IAppSessionListener.aidl new file mode 100644 index 0000000000000..228478a8909f4 --- /dev/null +++ b/core/java/com/android/internal/app/IAppSessionListener.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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.internal.app; + +oneway interface IAppSessionListener { + void onAppUnlocked(String packageName, int userId); + void onAppLocked(String packageName, int userId); +} diff --git a/core/java/com/android/internal/app/IAxSandboxManager.aidl b/core/java/com/android/internal/app/IAxSandboxManager.aidl new file mode 100644 index 0000000000000..ae75ec695c237 --- /dev/null +++ b/core/java/com/android/internal/app/IAxSandboxManager.aidl @@ -0,0 +1,56 @@ +package com.android.internal.app; + +import com.android.internal.app.IAppLockStateListener; +import com.android.internal.app.IAppSessionListener; +import com.android.internal.app.IHiddenNotificationListener; +import com.android.internal.app.HiddenNotificationInfo; + +/** + * @hide + */ +interface IAxSandboxManager { + int getAppLockState(String packageName); + boolean isPackageHidden(String packageName); + + void addLockedApp(String packageName); + void removeLockedApp(String packageName); + void setPackageHidden(String packageName, boolean hidden); + + List getLockedPackages(); + List getHiddenPackages(); + List getLockablePackages(); + + boolean isPackageLockable(String packageName); + + void unlockApp(String packageName, int userId); + void promptUnlock(String packageName, int userId); + + void registerAppLockStateListener(IAppLockStateListener listener); + void unregisterAppLockStateListener(IAppLockStateListener listener); + void registerAppSessionListener(IAppSessionListener listener); + void unregisterAppSessionListener(IAppSessionListener listener); + void registerHiddenNotificationListener(IHiddenNotificationListener listener); + void unregisterHiddenNotificationListener(IHiddenNotificationListener listener); + + List getHiddenNotifications(); + void onHiddenNotificationPosted(in HiddenNotificationInfo info); + void onHiddenNotificationRemoved(String key); + + boolean isPackageSandboxed(String packageName); + void addSandboxedPackage(String packageName); + void removeSandboxedPackage(String packageName); + List getSandboxedPackages(); + + void setRestrictedGids(String packageName, in int[] gids); + int[] getRestrictedGids(String packageName); + + boolean isSpoofSettingEnabled(String packageName, String settingKey); + void setSpoofSettingEnabled(String packageName, String settingKey, boolean enabled); + List getEnabledSpoofSettings(String packageName); + + boolean isSandboxDataIsolationEnabled(String packageName); + void setSandboxDataIsolationEnabled(String packageName, boolean enabled); + + String getSpoofedSetting(String callingPackage, String settingName); + String getFileVaultPath(); +} diff --git a/core/java/com/android/internal/app/IGameSpaceCallback.aidl b/core/java/com/android/internal/app/IGameSpaceCallback.aidl new file mode 100644 index 0000000000000..42b885ac1eb63 --- /dev/null +++ b/core/java/com/android/internal/app/IGameSpaceCallback.aidl @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025-2026 AxionOS 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.internal.app; + +oneway interface IGameSpaceCallback { + void onGameStart(String packageName); + void onGameLeave(); +} diff --git a/core/java/com/android/internal/app/IGameSpaceService.aidl b/core/java/com/android/internal/app/IGameSpaceService.aidl new file mode 100644 index 0000000000000..691caea94f066 --- /dev/null +++ b/core/java/com/android/internal/app/IGameSpaceService.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2025-2026 AxionOS 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.internal.app; + +import com.android.internal.app.IGameSpaceCallback; + +interface IGameSpaceService { + void registerCallback(IGameSpaceCallback callback); + void unregisterCallback(IGameSpaceCallback callback); +} diff --git a/core/java/com/android/internal/app/IHiddenNotificationListener.aidl b/core/java/com/android/internal/app/IHiddenNotificationListener.aidl new file mode 100644 index 0000000000000..8eb2659bfac31 --- /dev/null +++ b/core/java/com/android/internal/app/IHiddenNotificationListener.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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.internal.app; + +import com.android.internal.app.HiddenNotificationInfo; + +/** + * @hide + */ +oneway interface IHiddenNotificationListener { + void onHiddenNotificationPosted(in HiddenNotificationInfo info); + void onHiddenNotificationRemoved(String key); +} diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java index 65372be175821..a3fae32418ce1 100644 --- a/core/java/com/android/internal/app/LocalePicker.java +++ b/core/java/com/android/internal/app/LocalePicker.java @@ -155,8 +155,8 @@ public static List getAllAssetLocales(Context context, boolean isInD || l.getLanguage().isEmpty() || l.getCountry().isEmpty()) { continue; } - // Don't show the pseudolocales unless we're in developer mode. http://b/17190407. - if (!isInDeveloperMode && LocaleList.isPseudoLocale(l)) { + // Don't show the pseudolocales + if (LocaleList.isPseudoLocale(l)) { continue; } diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java index ceecf787901e4..a76d4ad7cbc31 100644 --- a/core/java/com/android/internal/app/LocaleStore.java +++ b/core/java/com/android/internal/app/LocaleStore.java @@ -31,6 +31,7 @@ import java.io.Serializable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -603,7 +604,8 @@ private static Set getTierLocales( boolean hasTargetParent = parent != null; String parentId = hasTargetParent ? parent.getId() : null; HashSet result = new HashSet<>(); - for (LocaleStore.LocaleInfo li : supportedLocaleInfos.values()) { + Collection currentLocaleInfos = new ArrayList<>(supportedLocaleInfos.values()); + for (LocaleStore.LocaleInfo li : currentLocaleInfos) { if (isShallIgnore(ignorables, li, translatedOnly)) { continue; } diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java index 9d5704141c93a..cf97d9885a2c0 100644 --- a/core/java/com/android/internal/app/SuspendedAppActivity.java +++ b/core/java/com/android/internal/app/SuspendedAppActivity.java @@ -317,7 +317,7 @@ public void onClick(DialogInterface dialog, int which) { try { final String[] errored = ipm.setPackagesSuspendedAsUser( new String[]{mSuspendedPackage}, false, null, null, null, 0, - mSuspendingPackage, mUserId /* suspendingUserId */, + mSuspendingPackage, mSuspendingUserId /* suspendingUserId */, mUserId /* targetUserId */); if (ArrayUtils.contains(errored, mSuspendedPackage)) { Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage); diff --git a/core/java/com/android/internal/content/F2fsUtils.java b/core/java/com/android/internal/content/F2fsUtils.java index 27f1b308ed9c3..afa8d7773b0b4 100644 --- a/core/java/com/android/internal/content/F2fsUtils.java +++ b/core/java/com/android/internal/content/F2fsUtils.java @@ -266,7 +266,10 @@ private static List getFilesRecursive(@NonNull File path) { final ArrayList files = new ArrayList<>(); for (File f : allFiles) { if (f.isDirectory()) { - files.addAll(getFilesRecursive(f)); + List inner = getFilesRecursive(f); + if (inner != null) { + files.addAll(inner); + } } else if (f.isFile()) { files.add(f); } diff --git a/core/java/com/android/internal/graphics/ColorUtils.java b/core/java/com/android/internal/graphics/ColorUtils.java index f210741e070bd..2a38f3098dcc5 100644 --- a/core/java/com/android/internal/graphics/ColorUtils.java +++ b/core/java/com/android/internal/graphics/ColorUtils.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.graphics.Color; import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.util.Log; import com.android.internal.graphics.cam.Cam; /** @@ -32,6 +33,8 @@ @RavenwoodKeepWholeClass public final class ColorUtils { + private static final String TAG = "ColorUtils"; + private static final double XYZ_WHITE_REFERENCE_X = 95.047; private static final double XYZ_WHITE_REFERENCE_Y = 100; private static final double XYZ_WHITE_REFERENCE_Z = 108.883; @@ -96,8 +99,10 @@ public static double calculateLuminance(@ColorInt int color) { */ public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) { if (Color.alpha(background) != 255) { - throw new IllegalArgumentException("background can not be translucent: #" - + Integer.toHexString(background)); + Log.w(TAG, String.format( + "Background should not be translucent: #%s", + Integer.toHexString(background))); + background = setAlphaComponent(background, 255); } if (Color.alpha(foreground) < 255) { // If the foreground is translucent, composite the foreground over the background @@ -149,8 +154,10 @@ public static int calculateMinimumBackgroundAlpha(@ColorInt int foreground, public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background, float minContrastRatio) { if (Color.alpha(background) != 255) { - throw new IllegalArgumentException("background can not be translucent: #" - + Integer.toHexString(background)); + Log.w(TAG, String.format( + "Background should not be translucent: #%s", + Integer.toHexString(background))); + background = setAlphaComponent(background, 255); } ContrastCalculator contrastCalculator = (fg, bg, alpha) -> { diff --git a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl index 512ace6145c6e..82b2c8256e4ff 100644 --- a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl +++ b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl @@ -32,4 +32,6 @@ interface IFontManager { FontConfig getFontConfig(); int updateFontFamily(in List request, int baseVersion); + + void clearUpdates(); } diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index 972c2ea403e07..d048e2d3bb9fe 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -71,6 +71,7 @@ public class SystemNotificationChannels { public static final String ACCESSIBILITY_HEARING_DEVICE = "ACCESSIBILITY_HEARING_DEVICE"; public static final String ACCESSIBILITY_SECURITY_POLICY = "ACCESSIBILITY_SECURITY_POLICY"; public static final String ABUSIVE_BACKGROUND_APPS = "ABUSIVE_BACKGROUND_APPS"; + public static String SLEEP = "SLEEP"; @VisibleForTesting static final String OBSOLETE_DO_NOT_DISTURB = "DO_NOT_DISTURB"; @@ -110,8 +111,8 @@ public static void createAll(Context context) { final NotificationChannel developerImportant = new NotificationChannel( DEVELOPER_IMPORTANT, context.getString(R.string.notification_channel_developer_important), - NotificationManager.IMPORTANCE_HIGH); - developer.setBlockable(true); + NotificationManager.IMPORTANCE_MIN); + developerImportant.setBlockable(true); channelsList.add(developerImportant); final NotificationChannel updates = new NotificationChannel( @@ -145,6 +146,7 @@ public static void createAll(Context context) { VPN, context.getString(R.string.notification_channel_vpn), NotificationManager.IMPORTANCE_LOW); + vpn.setBlockable(true); channelsList.add(vpn); final NotificationChannel time = new NotificationChannel( @@ -204,6 +206,11 @@ public static void createAll(Context context) { .build()); channelsList.add(systemChanges); + NotificationChannel sleepModeChanges = new NotificationChannel(SLEEP, + context.getString(R.string.notification_channel_sleep), + NotificationManager.IMPORTANCE_LOW); + channelsList.add(sleepModeChanges); + final NotificationChannel newFeaturePrompt = new NotificationChannel( ACCESSIBILITY_MAGNIFICATION, context.getString(R.string.notification_channel_accessibility_magnification), diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java index 21e0dc59db01d..b0b9c2cfddb4a 100644 --- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java @@ -452,7 +452,7 @@ private void processUidDelta(@Nullable Callback cb) { // Unit is 10ms. mDeltaTimes[i] = mCurTimes[i] - lastTimes[i]; if (mDeltaTimes[i] < 0) { - Slog.e(mTag, "Negative delta from freq time for uid: " + uid + if (DEBUG) Slog.e(mTag, "Negative delta from freq time for uid: " + uid + ", delta: " + mDeltaTimes[i]); return; } @@ -628,7 +628,7 @@ private void processUidDelta(@Nullable Callback cb) { cb.onUidCpuTime(uid, delta); } } else if (delta < 0) { - Slog.e(mTag, "Negative delta from active time for uid: " + uid + if (DEBUG) Slog.e(mTag, "Negative delta from active time for uid: " + uid + ", delta: " + delta); } } diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 6cabd504af676..665d44b0e754a 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -162,8 +162,11 @@ public void uncaughtException(Thread t, Throwable e) { } // Bring up crash dialog, wait for it to be dismissed - ActivityManager.getService().handleApplicationCrash( - mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e)); + final IActivityManager am = ActivityManager.getService(); + if (am != null) { + am.handleApplicationCrash( + mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e)); + } } catch (Throwable t2) { if (t2 instanceof DeadObjectException) { // System process is dead; ignore diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 168e4e5b347cd..43e2e6a92ce27 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -852,6 +852,7 @@ private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer, throw new RuntimeException(ex); } } + IoUtils.closeQuietly(sessionSocket); } if (writePipe != null) { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index e90b277f5eef0..53c03fbb6d66f 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -91,7 +91,7 @@ public class ZygoteInit { private static final String TAG = "Zygote"; - private static final boolean LOGGING_DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final boolean LOGGING_DEBUG = false; private static final String PROPERTY_DISABLE_GRAPHICS_DRIVER_PRELOADING = "ro.zygote.disable_gl_preload"; diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java index 7503fb1f99133..7f744b148f187 100644 --- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java +++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java @@ -264,7 +264,7 @@ private Boolean getFlagValueFromNewStorage(String flagPackageAndName) { try { return AconfigPackage.load(p); } catch (Exception e) { - Slog.e(LOG_TAG, "Failed to load aconfig package " + p, e); + //Slog.e(LOG_TAG, "Failed to load aconfig package " + p, e); return null; } }); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index 2903ca3ffd6e2..91c6781bc95c2 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -3000,9 +3000,8 @@ private static boolean hasDomainURLs(ParsingPackage pkg) { * ratio set. */ private static void setMaxAspectRatio(ParsingPackage pkg) { - // Default to (1.86) 16.7:9 aspect ratio for pre-O apps and unset for O and greater. - // NOTE: 16.7:9 was the max aspect ratio Android devices can support pre-O per the CDD. - float maxAspectRatio = pkg.getTargetSdkVersion() < O ? DEFAULT_PRE_O_MAX_ASPECT_RATIO : 0; + // Start at an unlimited aspect ratio unless we get a more restrictive one + float maxAspectRatio = 0; float packageMaxAspectRatio = pkg.getMaxAspectRatio(); if (packageMaxAspectRatio != 0) { diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 7cb7035f07353..92a01b06efb9e 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -34,6 +34,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; @@ -2731,6 +2732,16 @@ protected ViewGroup generateLayout(DecorView decor) { params.layoutInDisplayCutoutMode = mode; } + if (ActivityManager.isSystemReady()) { + try { + String packageName = context.getBasePackageName(); + if (ActivityManager.getService().shouldForceCutoutFullscreen(packageName)){ + params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; + } + } catch (RemoteException e) { + } + } + if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { if (a.getBoolean( diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java index b23515aa51f33..2d358433c6b7f 100644 --- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java +++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java @@ -41,6 +41,10 @@ public class ScreenDecorationsUtils { * If the associated display is not internal, will return 0. */ public static float getWindowCornerRadius(Context context) { + String callingPackage = context.getPackageManager().getNameForUid(android.os.Binder.getCallingUid()); + if ("com.google.android.apps.nexuslauncher".equals(callingPackage)) { + return 32f; + } final Resources resources = context.getResources(); if (!supportsRoundedCornersOnWindows(resources)) { return 0f; diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 0bca6c2efaa24..c0713dd1d16b8 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -413,4 +413,6 @@ oneway interface IStatusBar * @param displayId the id of the current display. */ void moveFocusedTaskToDesktop(int displayId); + + void restartSystemUI(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index b54bfaa28745e..aa40e92d74b72 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -249,4 +249,11 @@ interface IStatusBarService * Starts the default assistant app. */ void startAssist(in Bundle args); + + /** + * Toggle recent apps. + */ + void toggleRecentApps(); + + void restartSystemUI(); } diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java index 5f6ba7d555729..b136f4e64b653 100644 --- a/core/java/com/android/internal/util/ContrastColorUtil.java +++ b/core/java/com/android/internal/util/ContrastColorUtil.java @@ -819,8 +819,10 @@ public static double calculateLuminance(@ColorInt int color) { */ public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) { if (Color.alpha(background) != 255) { - Log.wtf(TAG, "background can not be translucent: #" - + Integer.toHexString(background)); + Log.w(TAG, String.format( + "Background should not be translucent: #%s", + Integer.toHexString(background))); + background = setAlphaComponent(background, 255); } if (Color.alpha(foreground) < 255) { // If the foreground is translucent, composite the foreground over the background diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java index bcad6fc85ca92..22014a411e49c 100644 --- a/core/java/com/android/internal/util/FileRotator.java +++ b/core/java/com/android/internal/util/FileRotator.java @@ -334,7 +334,15 @@ private String getActiveName(long currentTimeMillis) { long oldestActiveStart = Long.MAX_VALUE; final FileInfo info = new FileInfo(mPrefix); - for (String name : mBasePath.list()) { + String[] baseFiles = mBasePath.list(); + if (baseFiles == null) { + // no file in the path and create one starting now + info.startMillis = currentTimeMillis; + info.endMillis = Long.MAX_VALUE; + return info.build(); + } + + for (String name : baseFiles) { if (!info.parse(name)) continue; // pick the oldest active file which covers current time diff --git a/core/java/com/android/internal/util/PastyException.java b/core/java/com/android/internal/util/PastyException.java new file mode 100644 index 0000000000000..e956bb20dfc08 --- /dev/null +++ b/core/java/com/android/internal/util/PastyException.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018-2025 crDroid Android 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.internal.util; + +public class PastyException extends Exception { + + private static final long serialVersionUID = 666L; + + public PastyException(String message) { + super(message); + } +} diff --git a/core/java/com/android/internal/util/PastyUtils.java b/core/java/com/android/internal/util/PastyUtils.java new file mode 100644 index 0000000000000..513f216514e10 --- /dev/null +++ b/core/java/com/android/internal/util/PastyUtils.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018-2025 crDroid Android 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.internal.util; + +import android.os.Handler; +import android.os.HandlerThread; +import android.util.JsonReader; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.URL; + +import javax.net.ssl.HttpsURLConnection; + +/** + * Helper functions for uploading to Pasty + */ +public final class PastyUtils { + private static final String TAG = "PastyUtils"; + private static final String BASE_URL = "https://paste.projectmatrixx.com"; + private static final String API_URL = String.format("%s/documents", BASE_URL); + private static Handler handler; + + private PastyUtils() { + } + + /** + * Uploads {@code content} to Pasty + * + * @param content the content to upload to Pasty + * @param callback the callback to call on success / failure + */ + public static void upload(String content, UploadResultCallback callback) { + getHandler().post(new Runnable() { + @Override + public void run() { + try { + HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(API_URL).openConnection(); + try { + urlConnection.setRequestProperty("Content-Type", "text/plain"); + urlConnection.setRequestProperty("Accept-Charset", "UTF-8"); + urlConnection.setDoOutput(true); + + try (OutputStream output = urlConnection.getOutputStream()) { + output.write(content.getBytes("UTF-8")); + } + String key = ""; + try (JsonReader reader = new JsonReader( + new InputStreamReader(urlConnection.getInputStream(), "UTF-8"))) { + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + if (name.equals("key")) { + key = reader.nextString(); + break; + } else { + reader.skipValue(); + } + } + reader.endObject(); + } + if (!key.isEmpty()) { + callback.onSuccess(getUrl(key)); + } else { + String msg = "Failed to upload to Pasty: No key retrieved"; + callback.onFail(msg, new PastyException(msg)); + } + } finally { + urlConnection.disconnect(); + } + } catch (Exception e) { + callback.onFail("Failed to upload to Pasty", e); + } + } + }); + } + + /** + * Get the view URL from a key + */ + private static String getUrl(String key) { + return String.format("%s/%s", BASE_URL, key); + } + + private static Handler getHandler() { + if (handler == null) { + HandlerThread handlerThread = new HandlerThread("PastyThread"); + if (!handlerThread.isAlive()) + handlerThread.start(); + handler = new Handler(handlerThread.getLooper()); + } + return handler; + } + + public interface UploadResultCallback { + void onSuccess(String url); + + void onFail(String message, Exception e); + } +} diff --git a/core/java/com/android/internal/util/ViewCacheData.java b/core/java/com/android/internal/util/ViewCacheData.java new file mode 100644 index 0000000000000..5c916963450de --- /dev/null +++ b/core/java/com/android/internal/util/ViewCacheData.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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.internal.util; + +import android.app.ActivityThread; +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ViewCacheData { + private static final String FILE_NAME = "view-cache-data"; + private static final String KEY_DEPEND_UI = "depend_ui"; + + private final SharedPreferences mPrefs; + private final Map mCachedData = new HashMap<>(); + private StringBuilder mPendingBuilder = new StringBuilder(); + private String mPendingActivity; + private boolean mDirty; + private final List mDependUiList = new ArrayList<>(); + + public ViewCacheData(Context context) { + mPrefs = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + load(); + } + + private void load() { + Map all = mPrefs.getAll(); + for (Map.Entry e : all.entrySet()) { + String val = (String) e.getValue(); + if (val != null) { + String key = e.getKey(); + if (KEY_DEPEND_UI.equals(key)) { + parseDependUi(val); + } else { + mCachedData.put(key, val); + } + } + } + } + + private void parseDependUi(String val) { + for (String s : val.split("/")) { + try { + mDependUiList.add(Integer.parseInt(s)); + } catch (NumberFormatException ignored) { + } + } + } + + public synchronized List getLayoutsForActivity(String activityName) { + String val = mCachedData.get(activityName); + if (val == null) return null; + List ids = new ArrayList<>(); + for (String s : val.split("/")) { + try { + ids.add(Integer.parseInt(s)); + } catch (NumberFormatException ignored) { + } + } + return ids; + } + + public synchronized boolean isValid(int layoutId) { + return !mDependUiList.contains(layoutId); + } + + public synchronized void recordDependUi(int layoutId) { + if (!mDependUiList.contains(layoutId)) { + mDependUiList.add(layoutId); + String current = mDependUiList.isEmpty() ? "" : joinIds(mDependUiList); + mPrefs.edit().putString(KEY_DEPEND_UI, current).apply(); + } + } + + public synchronized void record(int layoutId) { + if (mPendingActivity == null) { + mPendingActivity = resolveProcessName(); + } + if (mPendingBuilder.length() > 0) { + mPendingBuilder.append("/"); + } + mPendingBuilder.append(layoutId); + mDirty = true; + } + + public synchronized void sync() { + if (!mDirty || mPendingActivity == null) return; + String current = mPendingBuilder.toString(); + String old = mCachedData.get(mPendingActivity); + if (!current.equals(old)) { + mCachedData.put(mPendingActivity, current); + mPrefs.edit().putString(mPendingActivity, current).apply(); + } + mPendingBuilder.setLength(0); + mPendingActivity = null; + mDirty = false; + } + + private static String resolveProcessName() { + try { + ActivityThread at = ActivityThread.currentActivityThread(); + return at != null ? at.getProcessName() : null; + } catch (Exception e) { + return null; + } + } + + private static String joinIds(List ids) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ids.size(); i++) { + if (i > 0) sb.append("/"); + sb.append(ids.get(i)); + } + return sb.toString(); + } +} diff --git a/core/java/com/android/internal/util/ViewCacheManager.java b/core/java/com/android/internal/util/ViewCacheManager.java new file mode 100644 index 0000000000000..df2863c6b8ea6 --- /dev/null +++ b/core/java/com/android/internal/util/ViewCacheManager.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * + * 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.internal.util; + +import android.content.ComponentName; +import android.content.Context; +import android.os.SystemProperties; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewRootImpl; +import android.view.ViewBackgroundThread; + +import java.util.ArrayList; +import java.util.List; + +public class ViewCacheManager { + private static final String TAG = "ViewCacheManager"; + private static final boolean ENABLED = SystemProperties.getBoolean( + "persist.sys.perf.view_cache", true); + private static volatile ViewCacheManager sInstance; + + private final SparseArray> mViewCache = new SparseArray<>(); + private final Object mLock = new Object(); + private ViewCacheData mData; + private boolean mActive; + private String mCurrentActivity; + + public static ViewCacheManager getInstance() { + if (sInstance == null) { + sInstance = new ViewCacheManager(); + } + return sInstance; + } + + public boolean isEnable() { + return ENABLED && mActive; + } + + public void onActivityAttached(Context context, ComponentName component) { + if (!ENABLED || component == null) return; + mActive = false; + mCurrentActivity = component.getClassName(); + synchronized (mLock) { + mViewCache.clear(); + } + if (mData == null) { + mData = new ViewCacheData(context); + } + List layoutIds = mData.getLayoutsForActivity(mCurrentActivity); + if (layoutIds == null || layoutIds.isEmpty()) return; + mActive = true; + ViewBackgroundThread.getHandler().post(() -> { + preInflateLayouts(context, layoutIds); + }); + } + + private void preInflateLayouts(Context context, List layoutIds) { + LayoutInflater inflater = LayoutInflater.from(context) + .cloneInContext(context); + for (int id : layoutIds) { + if (Thread.interrupted()) break; + if (mData != null && !mData.isValid(id)) continue; + try { + View view = inflater.inflate(id, null, false); + if (view != null) { + put(id, view); + } + } catch (Exception e) { + if (mData != null) { + mData.recordDependUi(id); + } + } + } + } + + public View tryGet(int layoutId) { + if (!ENABLED) return null; + synchronized (mLock) { + List entries = mViewCache.get(layoutId); + if (entries != null && !entries.isEmpty()) { + return entries.remove(0); + } + } + return null; + } + + public void put(int layoutId, View view) { + synchronized (mLock) { + List entries = mViewCache.get(layoutId); + if (entries == null) { + entries = new ArrayList<>(); + mViewCache.put(layoutId, entries); + } + entries.add(view); + } + } + + public void recordLayoutRes(int resource) { + if (mData != null) { + mData.record(resource); + } + } + + public void onTraversalEnd(ViewRootImpl vri) { + if (mData != null) { + mData.sync(); + } + mActive = false; + mCurrentActivity = null; + synchronized (mLock) { + mViewCache.clear(); + } + } +} diff --git a/core/java/com/android/internal/util/matrixx/DeviceConfigUtils.java b/core/java/com/android/internal/util/matrixx/DeviceConfigUtils.java new file mode 100644 index 0000000000000..d849a423d9314 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/DeviceConfigUtils.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 The Pixel Experience 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.internal.util.matrixx; + +import android.content.res.Resources; +import android.os.SystemProperties; +import android.provider.Settings; +import android.util.Log; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.android.internal.util.ArrayUtils; + +/** + * @hide + */ +public final class DeviceConfigUtils { + + private static final String TAG = DeviceConfigUtils.class.getSimpleName(); + private static final boolean DEBUG = false; + + private static Boolean sEnableDeviceConfigUtils = + SystemProperties.getBoolean("persist.sys.dchooks.enable", true); + + private static String[] getDeviceConfigsOverride() { + String[] globalDeviceConfigs = + Resources.getSystem().getStringArray(com.android.internal.R.array.global_device_configs_override); + String[] deviceConfigs = + Resources.getSystem().getStringArray(com.android.internal.R.array.device_configs_override); + String[] allDeviceConfigs = Arrays.copyOf(globalDeviceConfigs, globalDeviceConfigs.length + deviceConfigs.length); + System.arraycopy(deviceConfigs, 0, allDeviceConfigs, globalDeviceConfigs.length, deviceConfigs.length); + return allDeviceConfigs; + } + + public static boolean shouldDenyDeviceConfigControl(String namespace, String property) { + if (!sEnableDeviceConfigUtils) return false; + + if (DEBUG) Log.d(TAG, "shouldAllowDeviceConfigControl, namespace=" + namespace + ", property=" + property); + for (String p : getDeviceConfigsOverride()) { + String[] kv = p.split("="); + String fullKey = kv[0]; + String[] nsKey = fullKey.split("/"); + if (nsKey[0] == namespace && nsKey[1] == property){ + logd("shouldAllowDeviceConfigControl, deny, namespace=" + namespace + ", property=" + property); + return true; + } + } + logd("shouldAllowDeviceConfigControl, allow, namespace=" + namespace + ", property=" + property); + return false; + } + + public static void setDefaultProperties(String filterNamespace, String filterProperty) { + if (!sEnableDeviceConfigUtils) return; + + logd("setDefaultProperties"); + for (String p : getDeviceConfigsOverride()) { + String[] kv = p.split("="); + String fullKey = kv[0]; + String[] nsKey = fullKey.split("/"); + + String namespace = nsKey[0]; + String key = nsKey[1]; + + if (filterNamespace != null && filterNamespace == namespace){ + continue; + } + + if (filterProperty != null && filterProperty == key){ + continue; + } + + String value = ""; + if (kv.length > 1) { + value = kv[1]; + } + Settings.Config.putString(namespace, key, value, false); + } + } + + private static void logd(String msg) { + if (DEBUG) Log.d(TAG, msg); + } +} diff --git a/core/java/com/android/internal/util/matrixx/DisplayRefreshRateHelper.java b/core/java/com/android/internal/util/matrixx/DisplayRefreshRateHelper.java new file mode 100644 index 0000000000000..07a92ef33f892 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/DisplayRefreshRateHelper.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2022-2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.internal.util.matrixx; + +import static android.provider.Settings.System.MIN_REFRESH_RATE; +import static android.provider.Settings.System.PEAK_REFRESH_RATE; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.view.Display; + +import com.android.internal.R; + +import java.util.ArrayList; +import java.util.Comparator; + +/** @hide */ +public class DisplayRefreshRateHelper { + + private static final float DEFAULT_REFRESH_RATE = 60f; + + private static DisplayRefreshRateHelper sInstance = null; + + private final ArrayList mRefreshRateList = new ArrayList<>(); + private final Context mContext; + + public static DisplayRefreshRateHelper getInstance(Context context) { + if (sInstance == null) { + sInstance = new DisplayRefreshRateHelper(context); + } + return sInstance; + } + + private DisplayRefreshRateHelper(Context context) { + mContext = context; + initialize(); + } + + private void initialize() { + final Display.Mode mode = mContext.getDisplay().getMode(); + final Display.Mode[] modes = mContext.getDisplay().getSupportedModes(); + for (Display.Mode m : modes) { + if (m.getPhysicalWidth() == mode.getPhysicalWidth() && + m.getPhysicalHeight() == mode.getPhysicalHeight()) { + mRefreshRateList.add((int) m.getRefreshRate()); + } + } + mRefreshRateList.sort(Comparator.naturalOrder()); + } + + public ArrayList getSupportedRefreshRateList() { + return mRefreshRateList; + } + + public int getMinimumRefreshRate() { + final int refreshRate = mContext.getResources().getInteger( + R.integer.config_defaultRefreshRate); + final float defaultRefreshRate = refreshRate != 0 ? (float) refreshRate : DEFAULT_REFRESH_RATE; + final int ret = (int) Settings.System.getFloatForUser(mContext.getContentResolver(), + MIN_REFRESH_RATE, defaultRefreshRate, UserHandle.USER_SYSTEM); + if (mRefreshRateList.size() != 0 && !mRefreshRateList.contains(ret)) { + return mRefreshRateList.get(mRefreshRateList.size() - 1); + } + return ret; + } + + public int getPeakRefreshRate() { + final int refreshRate = mContext.getResources().getInteger( + R.integer.config_defaultPeakRefreshRate); + final float defaultPeakRefreshRate = refreshRate != 0 ? (float) refreshRate : DEFAULT_REFRESH_RATE; + final int ret = (int) Settings.System.getFloatForUser(mContext.getContentResolver(), + PEAK_REFRESH_RATE, defaultPeakRefreshRate, UserHandle.USER_SYSTEM); + if (mRefreshRateList.size() != 0 && !mRefreshRateList.contains(ret)) { + return mRefreshRateList.get(mRefreshRateList.size() - 1); + } + return ret; + } + + public ArrayList getRefreshRate() { + final ArrayList ret = new ArrayList<>(); + ret.add(getMinimumRefreshRate()); + ret.add(getPeakRefreshRate()); + return ret; + } + + public void setMinimumRefreshRate(int refreshRate) { + Settings.System.putFloatForUser(mContext.getContentResolver(), + MIN_REFRESH_RATE, (float) refreshRate, UserHandle.USER_SYSTEM); + } + + public void setPeakRefreshRate(int refreshRate) { + Settings.System.putFloatForUser(mContext.getContentResolver(), + PEAK_REFRESH_RATE, (float) refreshRate, UserHandle.USER_SYSTEM); + } + + public void setRefreshRate(int minRefreshRate, int peakRefreshRate) { + setMinimumRefreshRate(minRefreshRate); + setPeakRefreshRate(peakRefreshRate); + } + + public boolean isRefreshRateValid(int refreshRate) { + return mRefreshRateList.contains(refreshRate); + } +} diff --git a/core/java/com/android/internal/util/matrixx/FontController.java b/core/java/com/android/internal/util/matrixx/FontController.java new file mode 100644 index 0000000000000..b3088ad6a5c13 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/FontController.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2025-2026 AxionOS + * 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.internal.util.matrixx; + +import android.app.ActivityThread; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.os.SystemProperties; +import android.util.ArrayMap; +import android.util.Log; +import android.util.LruCache; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class FontController { + + private static final String TAG = "FontController"; + + private static FontController sInstance; + + public static final String GSF_FONT = "google-sans-flex"; + public static final String PROP_DEFAULT_FONT = "persist.sys.ax_default_font"; + public static final String PROP_OVERLAY_FONTS = "persist.sys.ax_overlay_fonts"; + private static final String SEPARATOR = ":"; + + private volatile String[] mFontConfig; + private volatile String mRawProp; + + private static final int IDX_BODY = 0; + private static final int IDX_BODY_MEDIUM = 1; + private static final int IDX_HEADLINE = 2; + private static final int IDX_HEADLINE_MEDIUM = 3; + private static final int FIELD_COUNT = 4; + + private final LruCache mCache = new LruCache<>(30); + + private static final Set EXCLUDED_APPS = new HashSet<>(Arrays.asList( + "it.subito", + "tv.arte.plus7", + "com.google.android.gm" + )); + + private static final Set WHITELIST_FONTS = new HashSet<>(Arrays.asList( + "serif", + "monospace", + "cursive", + "NotoSansSC", + "NotoSansTC", + "NotoSansJP", + "NotoSansKR", + "NotoColorEmoji", + "NotoColorEmojiFlags", + "NotoSansMono", + "RobotoMono", + "DroidSansMono", + "CutiveMono", + "CarroisGothicSC", + "source-code-pro", + "gs-clock", + "google-sans-flex-clock" + )); + + private static final String[][] WEIGHT_KEYWORDS = { + {"thin", "100"}, + {"extralight", "200"}, + {"light", "300"}, + {"semibold", "600"}, + {"extrabold", "800"}, + {"bold", "700"}, + {"medium", "500"}, + {"black", "900"}, + }; + + private static final Map VARIABLE_WEIGHT_MAP = new ArrayMap<>(); + static { + VARIABLE_WEIGHT_MAP.put("variable-display-large", 400); + VARIABLE_WEIGHT_MAP.put("variable-display-medium", 400); + VARIABLE_WEIGHT_MAP.put("variable-display-small", 400); + VARIABLE_WEIGHT_MAP.put("variable-headline-large", 400); + VARIABLE_WEIGHT_MAP.put("variable-headline-medium", 400); + VARIABLE_WEIGHT_MAP.put("variable-headline-small", 400); + VARIABLE_WEIGHT_MAP.put("variable-title-large", 400); + VARIABLE_WEIGHT_MAP.put("variable-title-medium", 500); + VARIABLE_WEIGHT_MAP.put("variable-title-small", 500); + VARIABLE_WEIGHT_MAP.put("variable-label-large", 500); + VARIABLE_WEIGHT_MAP.put("variable-label-medium", 500); + VARIABLE_WEIGHT_MAP.put("variable-label-small", 500); + VARIABLE_WEIGHT_MAP.put("variable-body-large", 400); + VARIABLE_WEIGHT_MAP.put("variable-body-medium", 400); + VARIABLE_WEIGHT_MAP.put("variable-body-small", 400); + VARIABLE_WEIGHT_MAP.put("variable-display-large-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-display-medium-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-display-small-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-headline-large-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-headline-medium-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-headline-small-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-title-large-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-title-medium-emphasized", 600); + VARIABLE_WEIGHT_MAP.put("variable-title-small-emphasized", 600); + VARIABLE_WEIGHT_MAP.put("variable-label-large-emphasized", 600); + VARIABLE_WEIGHT_MAP.put("variable-label-medium-emphasized", 600); + VARIABLE_WEIGHT_MAP.put("variable-label-small-emphasized", 600); + VARIABLE_WEIGHT_MAP.put("variable-body-large-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-body-medium-emphasized", 500); + VARIABLE_WEIGHT_MAP.put("variable-body-small-emphasized", 500); + } + + public static FontController get() { + if (sInstance == null) { + sInstance = new FontController(); + } + return sInstance; + } + + private FontController() {} + + public static String getBodyFont() { + return get().resolveConfig()[IDX_BODY]; + } + + public static String getBodyFontMedium() { + return get().resolveConfig()[IDX_BODY_MEDIUM]; + } + + public static String getHeadlineFont() { + return get().resolveConfig()[IDX_HEADLINE]; + } + + public static String getHeadlineFontMedium() { + return get().resolveConfig()[IDX_HEADLINE_MEDIUM]; + } + + public static boolean isCustomFontActive() { + return !GSF_FONT.equals(getBodyFont()); + } + + public static boolean isExcludedApp() { + String pkg = getCurrentPackageName(); + return pkg != null && EXCLUDED_APPS.contains(pkg); + } + + public static boolean isFontWhitelisted(String familyName) { + if (familyName == null) return false; + for (String wl : WHITELIST_FONTS) { + if (familyName.contains(wl)) return true; + } + return false; + } + + public static Typeface getOverrideTypeface(String familyName) { + if (familyName == null) return null; + if (isExcludedApp()) return null; + if (isFontWhitelisted(familyName)) return null; + if (!isCustomFontActive()) return null; + + FontController fc = get(); + String[] config = fc.resolveConfig(); + + if (familyName.equals(config[IDX_HEADLINE])) { + return Typeface.getSystemDefaultTypeface(config[IDX_HEADLINE]); + } + if (familyName.equals(config[IDX_HEADLINE_MEDIUM])) { + return Typeface.getSystemDefaultTypeface(config[IDX_HEADLINE_MEDIUM]); + } + if (familyName.equals(config[IDX_BODY_MEDIUM])) { + return Typeface.getSystemDefaultTypeface(config[IDX_BODY_MEDIUM]); + } + + boolean isVariable = familyName.startsWith("variable-"); + int weight = resolveWeight(familyName); + boolean isItalic = familyName.contains("italic"); + + int weightAdjustment = getFontWeightAdjustment(); + if (weightAdjustment != 0) { + weight = Math.min(1000, Math.max(100, weight + weightAdjustment)); + } + + Typeface base = resolveBase(config, familyName, isVariable, weight); + + if (weight == 400 && !isItalic && base == Typeface.DEFAULT) { + return Typeface.DEFAULT; + } + + Typeface cached = fc.mCache.get(familyName); + if (cached != null) return cached; + + Typeface result = Typeface.create(base, weight, isItalic); + fc.mCache.put(familyName, result); + return result; + } + + private static Typeface resolveBase(String[] config, String name, + boolean isVariable, int weight) { + if (!isVariable) return Typeface.DEFAULT; + + boolean isHeadlineRole = name.startsWith("variable-headline"); + boolean isMediumWeight = weight >= 500; + + String baseName; + if (isHeadlineRole) { + baseName = isMediumWeight ? config[IDX_HEADLINE_MEDIUM] : config[IDX_HEADLINE]; + } else { + baseName = isMediumWeight ? config[IDX_BODY_MEDIUM] : config[IDX_BODY]; + } + + Typeface base = Typeface.getSystemDefaultTypeface(baseName); + return base != null ? base : Typeface.DEFAULT; + } + + private static int resolveWeight(String name) { + if (name.startsWith("variable-")) { + Integer exact = VARIABLE_WEIGHT_MAP.get(name); + if (exact != null) return exact; + return name.endsWith("-emphasized") ? 500 : 400; + } + + for (String[] entry : WEIGHT_KEYWORDS) { + if (name.contains(entry[0])) return Integer.parseInt(entry[1]); + } + return 400; + } + + private static int getFontWeightAdjustment() { + try { + ActivityThread at = ActivityThread.currentActivityThread(); + if (at == null) return 0; + Resources res = at.getApplication().getResources(); + if (res == null) return 0; + Configuration cfg = res.getConfiguration(); + return cfg != null ? cfg.fontWeightAdjustment : 0; + } catch (Exception e) { + return 0; + } + } + + public static void clearCaches() { + get().mCache.evictAll(); + } + + private String[] resolveConfig() { + String defaultFont = SystemProperties.get(PROP_DEFAULT_FONT, GSF_FONT); + String raw = SystemProperties.get(PROP_OVERLAY_FONTS, ""); + + if (raw.equals(mRawProp) && mFontConfig != null) { + return mFontConfig; + } + + String[] config; + if (raw.isEmpty()) { + config = new String[] { defaultFont, defaultFont, defaultFont, defaultFont }; + } else { + String[] parts = raw.split(SEPARATOR, -1); + config = new String[FIELD_COUNT]; + for (int i = 0; i < FIELD_COUNT; i++) { + config[i] = (i < parts.length && !parts[i].isEmpty()) + ? parts[i] : defaultFont; + } + } + + mRawProp = raw; + mFontConfig = config; + logger("Font config: body=" + config[IDX_BODY] + + " bodyMed=" + config[IDX_BODY_MEDIUM] + + " headline=" + config[IDX_HEADLINE] + + " headlineMed=" + config[IDX_HEADLINE_MEDIUM]); + return config; + } + + private static String getCurrentPackageName() { + try { + return ActivityThread.currentPackageName(); + } catch (Exception e) { + return null; + } + } + + private static void logger(String msg) { + if (SystemProperties.getBoolean("persist.sys.ax_font_debug", false)) { + Log.d(TAG, msg); + } + } +} diff --git a/core/java/com/android/internal/util/matrixx/FullscreenTaskStackChangeListener.java b/core/java/com/android/internal/util/matrixx/FullscreenTaskStackChangeListener.java new file mode 100644 index 0000000000000..45de911a89d9b --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/FullscreenTaskStackChangeListener.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.android.internal.util.matrixx; + +import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.IActivityTaskManager; +import android.app.TaskStackListener; +import android.content.ComponentName; +import android.content.Context; +import android.os.RemoteException; +import android.util.Log; + +/** + * TaskStackListener that ignores freeform / mini-window focuses change + * + * @hide + */ +public abstract class FullscreenTaskStackChangeListener extends TaskStackListener { + + private static final String DEFAULT_TAG = "FullscreenTaskStackChangeListener"; + + private final ActivityManager mActivityManager; + private final ActivityTaskManager mActivityTaskManager; + private final IActivityTaskManager mIActivityTaskManager; + + private final boolean mObserveActivityChange; + + private boolean mDebug = false; + private String mDebugTag = DEFAULT_TAG; + + private boolean mListening = false; + + private String mTopPackage = ""; + private String mTopActivity = ""; + private int mTopTaskId = INVALID_TASK_ID; + + public FullscreenTaskStackChangeListener(Context context) { + this(context, false); + } + + public FullscreenTaskStackChangeListener(Context context, boolean observeActivity) { + mActivityManager = context.getSystemService(ActivityManager.class); + mActivityTaskManager = ActivityTaskManager.getInstance(); + mIActivityTaskManager = ActivityTaskManager.getService(); + mObserveActivityChange = observeActivity; + } + + public void setDebug(boolean debug) { + mDebug = debug; + } + + public void setDebugTag(String tag) { + mDebugTag = tag; + } + + public void setListening(boolean listening) { + if (mListening != listening) { + if (listening) { + mActivityTaskManager.registerTaskStackListener(this); + mListening = true; + } else { + mActivityTaskManager.unregisterTaskStackListener(this); + mListening = false; + } + } + } + + private void handleChange(String newPackageName, String newActivityName, int newTaskId) { + if (mTopPackage.equals(newPackageName) && mTopActivity.equals(newActivityName)) { + return; + } + mTopActivity = newActivityName; + if (!mObserveActivityChange && mTopPackage.equals(newPackageName)) { + return; + } + mTopPackage = newPackageName; + mTopTaskId = newTaskId; + if (mDebug) { + Log.d(mDebugTag, "Change: mTopPackage=" + mTopPackage + + ", mTopActivity=" + mTopActivity + + ", mTopTaskId=" + mTopTaskId); + } + onFullscreenTaskChanged(mTopPackage, mTopActivity, mTopTaskId); + } + + @Override + public void onTaskStackChanged() { + forceCheck(); + } + + @Override + public void onTaskFocusChanged(int taskId, boolean focused) { + if (focused) { + forceCheck(); + } + } + + public void forceCheck() { + try { + final ActivityTaskManager.RootTaskInfo info = mIActivityTaskManager.getFocusedRootTaskInfo(); + if (info == null) { + return; + } + if (info.getWindowingMode() == WINDOWING_MODE_FREEFORM) { + return; + } + final ComponentName topActivity = info.topActivity; + if (topActivity == null) { + return; + } + handleChange(topActivity.getPackageName(), topActivity.getClassName(), info.taskId); + } catch (RemoteException e) {} + } + + public String getTopPackageName() { + return mTopPackage; + } + + public String getTopActivityName() { + return mTopActivity; + } + + public int getTopTaskId() { + return mTopTaskId; + } + + public abstract void onFullscreenTaskChanged( + String packageName, String activityName, int taskId); +} diff --git a/core/java/com/android/internal/util/matrixx/OmniJawsClient.java b/core/java/com/android/internal/util/matrixx/OmniJawsClient.java new file mode 100644 index 0000000000000..8ad343fb6df0a --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/OmniJawsClient.java @@ -0,0 +1,469 @@ +/* + * Copyright (C) 2021 The OmniROM project + * Copyright (C) 2022-2025 crDroid Android 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.internal.util.matrixx; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import java.lang.ref.WeakReference; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +public class OmniJawsClient { + + private static final String TAG = "OmniJawsClient"; + private static final boolean DEBUG = false; + + public static final String SERVICE_PACKAGE = "org.omnirom.omnijaws"; + public static final Uri WEATHER_URI = Uri.parse("content://org.omnirom.omnijaws.provider/weather"); + public static final Uri SETTINGS_URI = Uri.parse("content://org.omnirom.omnijaws.provider/settings"); + public static final Uri HOURLY_URI = Uri.parse("content://org.omnirom.omnijaws.provider/hourly"); + public static final String WEATHER_UPDATE = SERVICE_PACKAGE + ".WEATHER_UPDATE"; + public static final String WEATHER_ERROR = SERVICE_PACKAGE + ".WEATHER_ERROR"; + + private static final String ICON_PACKAGE_DEFAULT = "org.omnirom.omnijaws"; + private static final String ICON_PREFIX_DEFAULT = "google_new_light"; + private static final String EXTRA_ERROR = "error"; + public static final int EXTRA_ERROR_NETWORK = 0; + public static final int EXTRA_ERROR_LOCATION = 1; + public static final int EXTRA_ERROR_DISABLED = 2; + + public static final String[] WEATHER_PROJECTION = { + "city", "wind_speed", "wind_direction", "condition_code", "temperature", + "humidity", "condition", "forecast_low", "forecast_high", "forecast_condition", + "forecast_condition_code", "time_stamp", "forecast_date", "pin_wheel", + "feels_like", "pressure", "uvi", "visibility", "dew_point", "sunrise", "sunset" + }; + + public static final String[] SETTINGS_PROJECTION = { + "enabled", "units", "provider", "setup", "icon_pack" + }; + + private static final DecimalFormat sNoDigitsFormat = new DecimalFormat("0"); + + private static OmniJawsClient sInstance; + + private WeatherInfo mCachedInfo; + private Resources mRes; + private String mPackageName; + private String mIconPrefix; + private String mSettingIconPackage; + private boolean mMetric; + + private final List> mObservers = new ArrayList<>(); + private WeatherUpdateReceiver mReceiver; + private boolean mWeatherReceiverRegistered = false; + + public static OmniJawsClient get() { + if (sInstance == null) { + synchronized (OmniJawsClient.class) { + if (sInstance == null) { + sInstance = new OmniJawsClient(); + } + } + } + return sInstance; + } + + public interface OmniJawsObserver { + void weatherUpdated(); + void weatherError(int errorReason); + default void updateSettings() {} + } + + private class WeatherUpdateReceiver extends BroadcastReceiver { + @Override public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + pruneDeadObservers(); + for (WeakReference ref : mObservers) { + OmniJawsObserver obs = ref.get(); + if (obs == null) continue; + if (WEATHER_UPDATE.equals(action)) { + obs.weatherUpdated(); + } else if (WEATHER_ERROR.equals(action)) { + obs.weatherError(intent.getIntExtra(EXTRA_ERROR, 0)); + } + } + } + } + + public Intent getSettingsIntent() { + return new Intent(Intent.ACTION_MAIN) + .setClassName(SERVICE_PACKAGE, SERVICE_PACKAGE + ".SettingsActivity"); + } + + public Intent getWeatherActivityIntent(Context context) { + if (isOmniJawsEnabled(context)) { + return new Intent(Intent.ACTION_MAIN) + .setClassName(SERVICE_PACKAGE, SERVICE_PACKAGE + ".WeatherActivity"); + } + return getSettingsIntent(); + } + + public WeatherInfo getWeatherInfo() { + return mCachedInfo; + } + + public void queryWeather(Context context) { + if (!isOmniJawsEnabled(context)) { + Log.w(TAG, "queryWeather while disabled"); + mCachedInfo = null; + return; + } + + try (Cursor weatherCursor = context.getContentResolver().query( + WEATHER_URI, WEATHER_PROJECTION, null, null, null)) { + + if (weatherCursor != null && weatherCursor.getCount() > 0) { + mCachedInfo = new WeatherInfo(); + List forecasts = new ArrayList<>(); + + for (int i = 0; i < weatherCursor.getCount(); i++) { + weatherCursor.moveToPosition(i); + if (i == 0) { + mCachedInfo.city = weatherCursor.getString(0); + mCachedInfo.windSpeed = getFormattedValue(weatherCursor.getFloat(1)); + mCachedInfo.windDirection = weatherCursor.getInt(2) + "\u00b0"; + mCachedInfo.conditionCode = weatherCursor.getInt(3); + mCachedInfo.temp = getFormattedValue(weatherCursor.getFloat(4)); + mCachedInfo.humidity = weatherCursor.getString(5); + mCachedInfo.condition = weatherCursor.getString(6); + mCachedInfo.timeStamp = Long.parseLong(weatherCursor.getString(11)); + mCachedInfo.pinWheel = weatherCursor.getString(13); + + int colFeelsLike = weatherCursor.getColumnIndex("feels_like"); + if (colFeelsLike != -1) mCachedInfo.feelsLike = weatherCursor.getFloat(colFeelsLike); + int colPressure = weatherCursor.getColumnIndex("pressure"); + if (colPressure != -1) mCachedInfo.pressure = weatherCursor.getFloat(colPressure); + int colUvi = weatherCursor.getColumnIndex("uvi"); + if (colUvi != -1) mCachedInfo.uvi = weatherCursor.getFloat(colUvi); + int colVisibility = weatherCursor.getColumnIndex("visibility"); + if (colVisibility != -1) mCachedInfo.visibility = weatherCursor.getFloat(colVisibility); + int colDewPoint = weatherCursor.getColumnIndex("dew_point"); + if (colDewPoint != -1) mCachedInfo.dewPoint = weatherCursor.getFloat(colDewPoint); + int colSunrise = weatherCursor.getColumnIndex("sunrise"); + if (colSunrise != -1) mCachedInfo.sunrise = weatherCursor.getLong(colSunrise); + int colSunset = weatherCursor.getColumnIndex("sunset"); + if (colSunset != -1) mCachedInfo.sunset = weatherCursor.getLong(colSunset); + } else { + DayForecast day = new DayForecast(); + day.low = getFormattedValue(weatherCursor.getFloat(7)); + day.high = getFormattedValue(weatherCursor.getFloat(8)); + day.condition = weatherCursor.getString(9); + day.conditionCode = weatherCursor.getInt(10); + day.date = weatherCursor.getString(12); + forecasts.add(day); + } + } + mCachedInfo.forecasts = forecasts; + } + } catch (Exception e) { + Log.e(TAG, "queryWeather: weather", e); + } + + try (Cursor settingsCursor = context.getContentResolver().query( + SETTINGS_URI, SETTINGS_PROJECTION, null, null, null)) { + + if (settingsCursor != null && settingsCursor.moveToFirst()) { + mMetric = settingsCursor.getInt(1) == 0; + if (mCachedInfo != null) { + mCachedInfo.tempUnits = getTemperatureUnit(); + mCachedInfo.windUnits = getWindUnit(); + mCachedInfo.provider = settingsCursor.getString(2); + mCachedInfo.iconPack = settingsCursor.getString(4); + } + } + } catch (Exception e) { + Log.e(TAG, "queryWeather: settings", e); + } + + if (mCachedInfo != null) { + try (Cursor hourlyCursor = context.getContentResolver().query( + HOURLY_URI, null, null, null, null)) { + if (hourlyCursor != null && hourlyCursor.getCount() > 0) { + List hourly = new ArrayList<>(); + while (hourlyCursor.moveToNext()) { + HourlyForecast h = new HourlyForecast(); + h.temperature = hourlyCursor.getFloat(hourlyCursor.getColumnIndex("hourly_temperature")); + h.conditionCode = hourlyCursor.getInt(hourlyCursor.getColumnIndex("hourly_condition_code")); + h.condition = hourlyCursor.getString(hourlyCursor.getColumnIndex("hourly_condition")); + h.timestamp = hourlyCursor.getLong(hourlyCursor.getColumnIndex("hourly_timestamp")); + h.humidity = hourlyCursor.getFloat(hourlyCursor.getColumnIndex("hourly_humidity")); + h.windSpeed = hourlyCursor.getFloat(hourlyCursor.getColumnIndex("hourly_wind_speed")); + hourly.add(h); + } + mCachedInfo.hourlyForecasts = hourly; + } + } catch (Exception e) { + Log.e(TAG, "queryWeather: hourly", e); + } + } + + updateSettings(context); + } + + private void updateSettings(Context context) { + String iconPack = (mCachedInfo != null) ? mCachedInfo.iconPack : null; + if (iconPack == null || TextUtils.isEmpty(iconPack)) { + loadDefaultIconsPackage(context); + } else if (!iconPack.equals(mSettingIconPackage)) { + mSettingIconPackage = iconPack; + loadCustomIconPackage(context); + } + } + + private void loadDefaultIconsPackage(Context context) { + mPackageName = ICON_PACKAGE_DEFAULT; + mIconPrefix = ICON_PREFIX_DEFAULT; + mSettingIconPackage = mPackageName + "." + mIconPrefix; + try { + mRes = context.getPackageManager().getResourcesForApplication(mPackageName); + } catch (Exception e) { + Log.w(TAG, "No default icon package found"); + mRes = null; + } + } + + private void loadCustomIconPackage(Context context) { + int idx = mSettingIconPackage.lastIndexOf("."); + if (idx == -1) { + loadDefaultIconsPackage(context); + return; + } + mPackageName = mSettingIconPackage.substring(0, idx); + mIconPrefix = mSettingIconPackage.substring(idx + 1); + try { + mRes = context.getPackageManager().getResourcesForApplication(mPackageName); + } catch (Exception e) { + Log.w(TAG, "Icon pack loading failed, fallback to default"); + loadDefaultIconsPackage(context); + } + } + + private static String getFormattedValue(float value) { + if (Float.isNaN(value)) return "-"; + String result = sNoDigitsFormat.format(value); + return result.equals("-0") ? "0" : result; + } + + public boolean isOmniJawsServiceInstalled(Context context) { + return isAvailableApp(context, SERVICE_PACKAGE); + } + + public boolean isOmniJawsEnabled(Context context) { + if (!isOmniJawsServiceInstalled(context)) return false; + + try (Cursor c = context.getContentResolver().query( + SETTINGS_URI, SETTINGS_PROJECTION, null, null, null)) { + return c != null && c.moveToFirst() && c.getInt(0) == 1; + } catch (Exception e) { + Log.e(TAG, "isOmniJawsEnabled", e); + return false; + } + } + + private boolean isAvailableApp(Context context, String pkg) { + try { + PackageManager pm = context.getPackageManager(); + pm.getPackageInfo(pkg, PackageManager.GET_ACTIVITIES); + int state = pm.getApplicationEnabledSetting(pkg); + return state != PackageManager.COMPONENT_ENABLED_STATE_DISABLED + && state != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; + } catch (NameNotFoundException | IllegalArgumentException e) { + return false; + } + } + + public void addObserver(Context context, OmniJawsObserver observer) { + if (observer == null) return; + removeObserver(context, observer); + mObservers.add(new WeakReference<>(observer)); + registerReceiverIfNeeded(context); + } + + public void removeObserver(Context context, OmniJawsObserver observer) { + if (observer == null) return; + Iterator> it = mObservers.iterator(); + while (it.hasNext()) { + OmniJawsObserver o = it.next().get(); + if (o == null || o == observer) { + it.remove(); + } + } + if (mObservers.isEmpty()) { + unregisterReceiver(context); + } + } + + private void pruneDeadObservers() { + try { + mObservers.removeIf(ref -> ref.get() == null); + } catch (Exception e) { + Log.w(TAG, "Exception occured while pruning, ignoring"); + } + } + + private void registerReceiverIfNeeded(Context context) { + if (!mWeatherReceiverRegistered && !mObservers.isEmpty()) { + if (mReceiver != null) { + try { + context.unregisterReceiver(mReceiver); + } catch (Exception ignored) {} + } + mReceiver = new WeatherUpdateReceiver(); + IntentFilter filter = new IntentFilter(); + filter.addAction(WEATHER_UPDATE); + filter.addAction(WEATHER_ERROR); + context.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED); + mWeatherReceiverRegistered = true; + } + } + + private void unregisterReceiver(Context context) { + if (mWeatherReceiverRegistered && mReceiver != null) { + try { + context.unregisterReceiver(mReceiver); + } catch (Exception ignored) {} + mWeatherReceiverRegistered = false; + } + } + + private String getTemperatureUnit() { + return mMetric ? "\u00b0C" : "\u00b0F"; + } + + private String getWindUnit() { + return mMetric ? "km/h" : "mph"; + } + + public Drawable getWeatherConditionImage(Context context, int conditionCode) { + if (mRes == null) { + loadDefaultIconsPackage(context); + } + try { + int resId = mRes.getIdentifier(mIconPrefix + "_" + conditionCode, "drawable", mPackageName); + Drawable d = mRes.getDrawable(resId, null); + return d != null ? d : getDefaultConditionImage(context); + } catch (Exception e) { + Log.e(TAG, "getWeatherConditionImage", e); + return getDefaultConditionImage(context); + } + } + + private Drawable getDefaultConditionImage(Context context) { + try { + Resources res = context.getPackageManager().getResourcesForApplication(ICON_PACKAGE_DEFAULT); + int resId = res.getIdentifier(ICON_PREFIX_DEFAULT + "_na", "drawable", ICON_PACKAGE_DEFAULT); + Drawable d = res.getDrawable(resId, null); + return d != null ? d : new ColorDrawable(Color.RED); + } catch (Exception e) { + return new ColorDrawable(Color.RED); + } + } + + public Drawable getResOmni(Context context, String iconOmni) { + if (mRes == null) loadDefaultIconsPackage(context); + try { + int resId = mRes.getIdentifier(iconOmni, "drawable", mPackageName); + Drawable d = mRes.getDrawable(resId, null); + return d != null ? d : new ColorDrawable(Color.RED); + } catch (Exception e) { + Log.e(TAG, "getResOmni", e); + return new ColorDrawable(Color.RED); + } + } + + public static class WeatherInfo { + public String city; + public String windSpeed; + public String windDirection; + public int conditionCode; + public String temp; + public String humidity; + public String condition; + public Long timeStamp; + public List forecasts; + public String tempUnits; + public String windUnits; + public String provider; + public String pinWheel; + public String iconPack; + + public float feelsLike = Float.NaN; + public float pressure = Float.NaN; + public float uvi = Float.NaN; + public float visibility = Float.NaN; + public float dewPoint = Float.NaN; + public long sunrise; + public long sunset; + public List hourlyForecasts; + + public String getLastUpdateTime() { + return new SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(new Date(timeStamp)); + } + + @Override + public String toString() { + return city + " @ " + new Date(timeStamp) + " | " + condition + " | " + temp; + } + } + + public static class DayForecast { + public String low; + public String high; + public int conditionCode; + public String condition; + public String date; + + @Override + public String toString() { + return "[" + date + " - " + low + "/" + high + " - " + condition + "]"; + } + } + + public static class HourlyForecast { + public float temperature; + public int conditionCode; + public String condition; + public long timestamp; + public float humidity; + public float windSpeed; + + @Override + public String toString() { + return "[" + new Date(timestamp) + " - " + temperature + " - " + condition + "]"; + } + } +} diff --git a/core/java/com/android/internal/util/matrixx/OnTheGoUtils.java b/core/java/com/android/internal/util/matrixx/OnTheGoUtils.java new file mode 100644 index 0000000000000..0263b880a74d0 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/OnTheGoUtils.java @@ -0,0 +1,106 @@ +/* +* +*/ + +package com.android.internal.util.matrixx; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.util.Log; + +import java.util.List; + +public class OnTheGoUtils { + + private static final String TAG = "OnTheGoUtils"; + + /** + * Checks if a specific package is installed. + * + * @param context The context to retrieve the package manager + * @param packageName The name of the package + * @return Whether the package is installed or not. + */ + public static boolean isPackageInstalled(Context context, String packageName) { + PackageManager pm = context.getPackageManager(); + try { + if (pm != null) { + List packages = pm.getInstalledApplications(0); + for (ApplicationInfo packageInfo : packages) { + if (packageInfo.packageName.equals(packageName)) { + return true; + } + } + } + } catch (Exception e) { + Log.e(TAG, "Error: " + e.getMessage()); + } + return false; + } + + /** + * Checks if a specific service is running. + * + * @param context The context to retrieve the activity manager + * @param serviceName The name of the service + * @return Whether the service is running or not + */ + public static boolean isServiceRunning(Context context, String serviceName) { + ActivityManager activityManager = (ActivityManager) context + .getSystemService(Context.ACTIVITY_SERVICE); + List services = activityManager + .getRunningServices(Integer.MAX_VALUE); + + if (services != null) { + for (ActivityManager.RunningServiceInfo info : services) { + if (info.service != null) { + if (info.service.getClassName() != null && info.service.getClassName() + .equalsIgnoreCase(serviceName)) { + return true; + } + } + } + } + + return false; + } + + /** + * Check if system has a camera. + * + * @param context + * @return + */ + public static boolean hasCamera(final Context context) { + final PackageManager pm = context.getPackageManager(); + return pm != null && pm.hasSystemFeature(PackageManager.FEATURE_CAMERA); + } + + /** + * Check if system has a front camera. + * + * @param context + * @return + */ + public static boolean hasFrontCamera(final Context context) { + final PackageManager pm = context.getPackageManager(); + return pm != null && pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT); + } +} diff --git a/core/java/com/android/internal/util/matrixx/PixelPropsUtils.java b/core/java/com/android/internal/util/matrixx/PixelPropsUtils.java new file mode 100644 index 0000000000000..666e9fe0426cd --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/PixelPropsUtils.java @@ -0,0 +1,558 @@ +/* + * Copyright (C) 2020 The Pixel Experience Project + * 2022 StatiXOS + * 2021-2022 crDroid Android Project + * SPDX-FileCopyrightText: Evolution X + * SPDX-License-Identifier: Apache-2.0 + * + * 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.internal.util.matrixx; + +import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.app.Application; +import android.app.TaskStackListener; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Binder; +import android.os.Build; +import android.os.Process; +import android.os.SystemProperties; +import android.os.UserHandle; +import android.provider.Settings; +import android.util.Log; + +import com.android.internal.R; +import com.android.internal.util.matrixx.Utils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +/** + * @hide + */ +public final class PixelPropsUtils { + + private static final String PACKAGE_ARCORE = "com.google.ar.core"; + private static final String PACKAGE_GMS = "com.google.android.gms"; + private static final String PACKAGE_NEXUS_LAUNCHER = "com.google.android.apps.nexuslauncher"; + private static final String PACKAGE_PHOTOS = "com.google.android.apps.photos"; + private static final String PACKAGE_SI = "com.google.android.settings.intelligence"; + private static final String PACKAGE_SNAPCHAT = "com.snapchat.android"; + + private static final String TAG = PixelPropsUtils.class.getSimpleName(); + private static final boolean DEBUG = false; + + private static final String sDeviceFingerprint = + SystemProperties.get("ro.product.fingerprint", Build.FINGERPRINT); + + private static final Map sPixelXLProps = Map.of( + "BRAND", "google", + "MANUFACTURER", "Google", + "DEVICE", "marlin", + "PRODUCT", "marlin", + "HARDWARE", "marlin", + "ID", "QP1A.191005.007.A3", + "MODEL", "Pixel XL", + "FINGERPRINT", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys" + ); + + private static final Map propsToChangeGeneric; + private static final Map propsToChangeRecentPixel; + private static final Map propsToChangePixelTablet; + private static final Map> propsToKeep; + + private static volatile Set mLauncherPkgs; + private static volatile Set mExemptedUidPkgs; + + // Tensor devices: Pixel 6 and above + private static final Pattern TENSOR_PIXEL_PATTERN = + Pattern.compile("^Pixel (([6-9]|[1-9][0-9])[a-zA-Z ]*)$"); + + // Mainline (first-party SoC) devices: Pixel 8 and above + private static final Pattern MAINLINE_PIXEL_PATTERN = + Pattern.compile("^Pixel (([89]|[1-9][0-9])([a-zA-Z].*)?)$"); + + // Any supported Pixel: Pixel 3 and above (covers full GMS support window + current) + private static final Pattern SUPPORTED_PIXEL_PATTERN = + Pattern.compile("^Pixel ([3-9]|[1-9][0-9])([a-zA-Z ].*)?$"); + + // Packages to Spoof as the most recent Pixel device + private static final Set packagesToChangeRecentPixel = new HashSet<>(Arrays.asList( + "com.amazon.avod.thirdpartyclient", + "com.android.chrome", + "com.breel.wallpapers20", + "com.disney.disneyplus", + "com.google.android.aicore", + "com.google.android.apps.accessibility.magnifier", + "com.google.android.apps.aiwallpapers", + "com.google.android.apps.bard", + "com.google.android.apps.customization.pixel", + "com.google.android.apps.emojiwallpaper", + "com.google.android.apps.pixel.agent", + "com.google.android.apps.pixel.creativeassistant", + "com.google.android.apps.pixel.nowplaying", + "com.google.android.apps.pixel.psi", + "com.google.android.apps.pixel.subzero", + "com.google.android.apps.pixel.support", + "com.google.android.apps.privacy.wildlife", + "com.google.android.apps.subscriptions.red", + "com.google.android.apps.wallpaper", + "com.google.android.apps.wallpaper.pixel", + "com.google.android.apps.weather", + "com.google.android.googlequicksearchbox", + "com.google.android.pcs", + "com.google.android.wallpaper.effects", + "com.google.pixel.livewallpaper", + "com.microsoft.android.smsorganizer", + "com.nhs.online.nhsonline", + "com.nothing.smartcenter", + "com.realme.link", + "in.startv.hotstar", + "jp.id_credit_sp2.android" + )); + + private static final Set customGoogleCameraPackages = new HashSet<>(Arrays.asList( + "com.google.android.MTCL83", + "com.google.android.UltraCVM", + "com.google.android.apps.cameralite" + )); + + private static volatile boolean sIsExcluded; + private static volatile String sProcessName; + + private static final boolean sIsCustomForkBuild = detectCustomFork(); + private static final boolean sIsMainlineDevice = detectMainlinePixelDevice(); + + // Cached spoof settings — refreshed by ContentObserver, avoids per-call Settings reads + private static volatile boolean sPhotosSpoofEnabled = true; + private static volatile boolean sSnapchatSpoofEnabled = false; + private static volatile boolean sPixelPropsSpoofEnabled = true; + private static volatile boolean sInitialized = false; + + private static boolean detectCustomFork() { + char[] k = new char[]{'d','e','v','o','l','u','t','i','o','n'}; + String needle = new String(k); + + String[] props = { + SystemProperties.get("ro.build.display.id", ""), + SystemProperties.get("ro.modversion", ""), + SystemProperties.get("ro.evolution.version", ""), + SystemProperties.get("ro.build.flavor", "") + }; + + for (String p : props) { + if (p != null && p.toLowerCase().contains(needle)) { + return true; + } + } + return false; + } + + public static boolean isCustomForkBuild() { + return sIsCustomForkBuild; + } + + static { + propsToKeep = new HashMap<>(); + propsToKeep.put(PACKAGE_SI, new ArrayList<>(Collections.singletonList("FINGERPRINT"))); + propsToChangeGeneric = new HashMap<>(); + propsToChangeGeneric.put("TYPE", "user"); + propsToChangeGeneric.put("TAGS", "release-keys"); + propsToChangeRecentPixel = new HashMap<>(); + propsToChangeRecentPixel.put("BRAND", "google"); + propsToChangeRecentPixel.put("BOARD", "mustang"); + propsToChangeRecentPixel.put("MANUFACTURER", "Google"); + propsToChangeRecentPixel.put("DEVICE", "mustang"); + propsToChangeRecentPixel.put("PRODUCT", "mustang"); + propsToChangeRecentPixel.put("HARDWARE", "mustang"); + propsToChangeRecentPixel.put("MODEL", "Pixel 10 Pro XL"); + propsToChangeRecentPixel.put("ID", "CP1A.260505.005"); + propsToChangeRecentPixel.put("FINGERPRINT", "google/mustang/mustang:16/CP1A.260505.005/15081906:user/release-keys"); + propsToChangePixelTablet = new HashMap<>(); + propsToChangePixelTablet.put("BRAND", "google"); + propsToChangePixelTablet.put("BOARD", "tangorpro"); + propsToChangePixelTablet.put("MANUFACTURER", "Google"); + propsToChangePixelTablet.put("DEVICE", "tangorpro"); + propsToChangePixelTablet.put("PRODUCT", "tangorpro"); + propsToChangePixelTablet.put("HARDWARE", "tangorpro"); + propsToChangePixelTablet.put("MODEL", "Pixel Tablet"); + propsToChangePixelTablet.put("ID", "CP1A.260505.005"); + propsToChangePixelTablet.put("FINGERPRINT", "google/tangorpro/tangorpro:16/CP1A.260505.005/15081906:user/release-keys"); + } + + public static String getBuildID(String fingerprint) { + Pattern pattern = Pattern.compile("([A-Za-z0-9]+\\.\\d+\\.\\d+\\.\\w+)"); + Matcher matcher = pattern.matcher(fingerprint); + + if (matcher.find()) { + return matcher.group(1); + } + return ""; + } + + public static String getDeviceName(String fingerprint) { + String[] parts = fingerprint.split("/"); + if (parts.length >= 2) { + return parts[1]; + } + return ""; + } + + public static void init(Context context) { + if (sInitialized || Process.isIsolated() || context == null) return; + sInitialized = true; + registerSpoofSettingsObserver(context); + } + + private static void registerSpoofSettingsObserver(Context context) { + final ContentResolver cr = context.getContentResolver(); + final Runnable refresh = () -> { + try { + sPhotosSpoofEnabled = Settings.Secure.getInt( + cr, Settings.Secure.PI_PHOTOS_SPOOF, 1) == 1; + sSnapchatSpoofEnabled = Settings.Secure.getInt( + cr, Settings.Secure.PI_SNAPCHAT_SPOOF, 0) == 1; + sPixelPropsSpoofEnabled = Settings.Secure.getInt( + cr, Settings.Secure.PI_PP_SPOOF, 1) == 1; + } catch (Throwable t) { + // Settings provider not ready yet; cache stays at safe defaults + } + }; + try { + final android.database.ContentObserver observer = + new android.database.ContentObserver(null) { + @Override + public void onChange(boolean selfChange) { refresh.run(); } + }; + cr.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.PI_PHOTOS_SPOOF), false, observer); + cr.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.PI_SNAPCHAT_SPOOF), false, observer); + cr.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.PI_PP_SPOOF), false, observer); + } catch (Throwable t) { + // Observer registration failed; cached defaults remain + } + refresh.run(); + } + + private static boolean isGoogleCameraPackage(String packageName) { + return packageName.contains("GoogleCamera") + || customGoogleCameraPackages.contains(packageName); + } + + private static void applyAppSpecificProps(String packageName) { + if (packageName.equals(PACKAGE_PHOTOS)) { + if (sPhotosSpoofEnabled) { + sPixelXLProps.forEach(PixelPropsUtils::setPropValue); + } + return; + } + + if (packageName.equals(PACKAGE_SNAPCHAT)) { + if (sSnapchatSpoofEnabled) { + sPixelXLProps.forEach(PixelPropsUtils::setPropValue); + } + } + } + + public static void setProps(Context context) { + if (sIsCustomForkBuild) { + if (DEBUG) Log.d(TAG, "Custom fork detected → disabling prop spoofing"); + return; + } + + if (Process.isIsolated()) { + if (DEBUG) Log.d(TAG, "Skipping setProps in isolated process"); + return; + } + + final String packageName = context.getPackageName(); + final String processName = Application.getProcessName(); + if (packageName == null || processName == null || packageName.isEmpty()) { + return; + } + + sProcessName = processName; + + init(context); + + Map propsToChange = new HashMap<>(); + + propsToChangeGeneric.forEach((k, v) -> setPropValue(k, v)); + + sIsExcluded = isGoogleCameraPackage(packageName); + + if (!sIsExcluded + && packagesToChangeRecentPixel.contains(packageName) + && !sIsMainlineDevice + && sPixelPropsSpoofEnabled) { + + if (isDeviceTablet(context)) { + propsToChange.putAll(propsToChangePixelTablet); + } else { + propsToChange.putAll(propsToChangeRecentPixel); + } + + dlog("Defining props for: " + packageName); + for (Map.Entry prop : propsToChange.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + if (propsToKeep.containsKey(packageName) && propsToKeep.get(packageName).contains(key)) { + dlog("Not defining " + key + " prop for: " + packageName); + continue; + } + dlog("Defining " + key + " prop for: " + packageName); + setPropValue(key, value); + } + } + + // Set proper indexing fingerprint + if (packageName.equals(PACKAGE_SI)) { + setPropValue("FINGERPRINT", String.valueOf(Build.TIME)); + return; + } + if (packageName.equals(PACKAGE_ARCORE)) { + setPropValue("FINGERPRINT", sDeviceFingerprint); + return; + } + applyAppSpecificProps(packageName); + } + + private static boolean isDeviceTablet(Context context) { + if (context == null) { + return false; + } + Configuration config = context.getResources().getConfiguration(); + if (config == null) return false; + return config.smallestScreenWidthDp >= 600; + } + + public static void setPropValue(String key, Object value) { + try { + Field field = getBuildClassField(key); + if (field != null) { + field.setAccessible(true); + if (field.getType() == int.class) { + if (value instanceof String) { + field.set(null, Integer.parseInt((String) value)); + } else if (value instanceof Integer) { + field.set(null, (Integer) value); + } + } else if (field.getType() == long.class) { + if (value instanceof String) { + field.set(null, Long.parseLong((String) value)); + } else if (value instanceof Long) { + field.set(null, (Long) value); + } + } else { + field.set(null, value.toString()); + } + field.setAccessible(false); + dlog("Set prop " + key + " to " + value); + } else { + Log.e(TAG, "Field " + key + " not found in Build or Build.VERSION classes"); + } + } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) { + Log.e(TAG, "Failed to set prop " + key, e); + } + } + + private static Field getBuildClassField(String key) throws NoSuchFieldException { + try { + Field field = Build.class.getDeclaredField(key); + dlog("Field " + key + " found in Build.class"); + return field; + } catch (NoSuchFieldException e) { + Field field = Build.VERSION.class.getDeclaredField(key); + dlog("Field " + key + " found in Build.VERSION.class"); + return field; + } + } + + private static String[] getStringArrayResSafely(int resId) { + String[] strArr = Resources.getSystem().getStringArray(resId); + if (strArr == null) strArr = new String[0]; + return strArr; + } + + public static boolean isPackageGoogle(String pkg) { + return pkg != null && pkg.toLowerCase().contains("google"); + } + + private static Set getLauncherPkgs() { + synchronized (PixelPropsUtils.class) { + if (mLauncherPkgs == null || mLauncherPkgs.isEmpty()) { + mLauncherPkgs = + new HashSet<>( + Arrays.asList( + getStringArrayResSafely(R.array.config_launcherPackages))); + } + return mLauncherPkgs; + } + } + + private static Set getExemptedUidPkgs() { + synchronized (PixelPropsUtils.class) { + if (mExemptedUidPkgs == null || mExemptedUidPkgs.isEmpty()) { + mExemptedUidPkgs = new HashSet<>(); + mExemptedUidPkgs.add(PACKAGE_GMS); + mExemptedUidPkgs.addAll(getLauncherPkgs()); + } + return mExemptedUidPkgs; + } + } + + public static boolean isNexusLauncher(Context context) { + try { + return PACKAGE_NEXUS_LAUNCHER.equals( + context.getPackageManager().getNameForUid(android.os.Binder.getCallingUid())); + } catch (Exception e) { + return false; + } + } + + public static boolean isSystemLauncher(Context context) { + try { + return isSystemLauncherInternal( + context.getPackageManager().getNameForUid(android.os.Binder.getCallingUid())); + } catch (Exception e) { + return false; + } + } + + public static boolean isSystemLauncher(int callingUid) { + try { + return isSystemLauncherInternal( + ActivityThread.getPackageManager().getNameForUid(callingUid)); + } catch (Exception e) { + return false; + } + } + + public static boolean isSystemLauncherInternal(String callerPackage) { + return getLauncherPkgs().contains(callerPackage); + } + + public static boolean shouldBypassTaskPermission(int callingUid) { + for (String pkg : getExemptedUidPkgs()) { + try { + ApplicationInfo appInfo = + ActivityThread.getPackageManager() + .getApplicationInfo(pkg, 0, UserHandle.getUserId(callingUid)); + if (appInfo.uid == callingUid) { + return true; + } + } catch (Exception e) { + dlog("shouldBypassTaskPermission: failed to get appInfo for uid " + callingUid + ": " + e.getMessage()); + } + } + return false; + } + + public static boolean shouldBypassManageActivityTaskPermission(Context context) { + final int callingUid = Binder.getCallingUid(); + return isSystemLauncher(callingUid) + || isPackageGoogle(context.getPackageManager().getNameForUid(callingUid)); + } + + public static boolean shouldBypassMonitorInputPermission(Context context) { + final int callingUid = Binder.getCallingUid(); + return shouldBypassTaskPermission(callingUid) + || isPackageGoogle(context.getPackageManager().getNameForUid(callingUid)); + } + + // Whitelist of package names to bypass FGS type validation + public static boolean shouldBypassFGSValidation(String packageName) { + if (Arrays.asList(getStringArrayResSafely(R.array.config_fgsTypeValidationBypassPackages)) + .contains(packageName)) { + dlog("shouldBypassFGSValidation: " + + "Bypassing FGS type validation for whitelisted app: " + + packageName); + return true; + } + return false; + } + + // Whitelist of package names to bypass alarm manager validation + public static boolean shouldBypassAlarmManagerValidation(String packageName) { + if (Arrays.asList( + getStringArrayResSafely( + R.array.config_alarmManagerValidationBypassPackages)) + .contains(packageName)) { + dlog("shouldBypassAlarmManagerValidation: " + + "Bypassing alarm manager validation for whitelisted app: " + + packageName); + return true; + } + return false; + } + + // Whitelist of package names to bypass broadcast receiver validation + public static boolean shouldBypassBroadcastReceiverValidation(String packageName) { + if (Arrays.asList( + getStringArrayResSafely( + R.array.config_broadcastReceiverValidationBypassPackages)) + .contains(packageName)) { + dlog("shouldBypassBroadcastReceiverValidation: " + + "Bypassing broadcast receiver validation for whitelisted app: " + + packageName); + return true; + } + return false; + } + + private static boolean detectMainlinePixelDevice() { + String model = SystemProperties.get("ro.product.model", "").trim(); + boolean isPixelSoC = "Google".equalsIgnoreCase( + SystemProperties.get("ro.soc.manufacturer")); + return isPixelSoC && MAINLINE_PIXEL_PATTERN.matcher(model).matches(); + } + + public static boolean isMainlinePixelDevice() { + return sIsMainlineDevice; + } + + public static boolean isTensorPixelDevice() { + String model = SystemProperties.get("ro.product.model", "").trim(); + // Tensor devices are always Google SoC + boolean isPixelSoC = "Google".equalsIgnoreCase( + SystemProperties.get("ro.soc.manufacturer")); + return isPixelSoC && TENSOR_PIXEL_PATTERN.matcher(model).matches(); + } + + public static boolean isSupportedPixelDevice() { + String model = SystemProperties.get("ro.product.model", "").trim(); + return SUPPORTED_PIXEL_PATTERN.matcher(model).matches(); + } + + public static void dlog(String msg) { + if (DEBUG) Log.d(TAG, "[" + sProcessName + "] " + msg); + } +} diff --git a/core/java/com/android/internal/util/matrixx/SystemRestartUtils.java b/core/java/com/android/internal/util/matrixx/SystemRestartUtils.java new file mode 100644 index 0000000000000..b9b7cdc9a0632 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/SystemRestartUtils.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2023 Rising OS Android 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.internal.util.matrixx; + +import android.app.AlertDialog; +import android.app.IActivityManager; +import android.app.ActivityManager; +import android.content.Context; +import android.content.DialogInterface; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Process; +import android.os.RemoteException; +import android.os.ServiceManager; + +import com.android.internal.R; +import com.android.internal.statusbar.IStatusBarService; + +import java.lang.ref.WeakReference; + +import java.util.List; + +public class SystemRestartUtils { + + private static final int RESTART_TIMEOUT = 1000; + + public static void showSystemRestartDialog(Context context) { + new AlertDialog.Builder(context) + .setTitle(R.string.system_restart_title) + .setMessage(R.string.system_restart_message) + .setPositiveButton(R.string.ok, (dialog, id) -> { + Handler handler = new Handler(); + handler.postDelayed(() -> restartSystem(context), RESTART_TIMEOUT); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + public static void powerOffSystem(Context context) { + new PowerOffSystemTask(context).execute(); + } + + private static class PowerOffSystemTask extends AsyncTask { + private final WeakReference mContext; + + PowerOffSystemTask(Context context) { + mContext = new WeakReference<>(context); + } + + @Override + protected Void doInBackground(Void... params) { + try { + IStatusBarService mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + if (mBarService != null) { + try { + Thread.sleep(RESTART_TIMEOUT); + mBarService.shutdown(); + } catch (RemoteException | InterruptedException e) { + e.printStackTrace(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } + + public static void restartSystem(Context context) { + new RestartSystemTask(context).execute(); + } + + private static class RestartSystemTask extends AsyncTask { + private final WeakReference mContext; + + RestartSystemTask(Context context) { + mContext = new WeakReference<>(context); + } + + @Override + protected Void doInBackground(Void... params) { + try { + IStatusBarService mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + if (mBarService != null) { + try { + Thread.sleep(RESTART_TIMEOUT); + mBarService.reboot(false, null); + } catch (RemoteException | InterruptedException e) { + e.printStackTrace(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } + + private static void showRestartDialog(Context context, int title, int message, Runnable action) { + new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(R.string.ok, (dialog, id) -> { + Handler handler = new Handler(); + handler.postDelayed(action, RESTART_TIMEOUT); + }) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + public static void restartProcess(Context context, String processName) { + new RestartTask(context, processName).execute(); + } + + private static class RestartTask extends AsyncTask { + private final WeakReference mContext; + private final String mPackageName; + + RestartTask(Context context, String packageName) { + mContext = new WeakReference<>(context); + mPackageName = packageName; + } + + @Override + protected Void doInBackground(Void... params) { + try { + ActivityManager am = (ActivityManager) mContext.get().getSystemService(Context.ACTIVITY_SERVICE); + if (am != null) { + List runningProcesses = am.getRunningAppProcesses(); + for (ActivityManager.RunningAppProcessInfo appProcess : runningProcesses) { + if (appProcess.pkgList != null) { + for (String pkg : appProcess.pkgList) { + if (pkg.equals(mPackageName)) { + Process.killProcess(appProcess.pid); + return null; + } + } + } + } + } + } catch (Exception e) {} + return null; + } + } + + public static void showSettingsRestartDialog(Context context) { + showRestartDialog(context, R.string.settings_restart_title, R.string.settings_restart_message, () -> restartProcess(context, "com.android.settings")); + } + + public static void showSystemUIRestartDialog(Context context) { + showRestartDialog(context, R.string.systemui_restart_title, R.string.systemui_restart_message, () -> restartProcess(context, "com.android.systemui")); + } +} diff --git a/core/java/com/android/internal/util/matrixx/ThemeUtils.java b/core/java/com/android/internal/util/matrixx/ThemeUtils.java new file mode 100644 index 0000000000000..c63fa64f66eb5 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/ThemeUtils.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2014 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.internal.util.matrixx; + +import static android.os.UserHandle.USER_SYSTEM; + +import android.util.PathParser; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.om.IOverlayManager; +import android.content.om.OverlayInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ProviderInfo; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.content.res.Configuration; +import android.database.Cursor; +import android.graphics.Typeface; +import android.graphics.Path; +import android.graphics.drawable.AdaptiveIconDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.PathShape; +import android.net.Uri; +import android.os.BatteryManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class ThemeUtils { + + public static final String TAG = "ThemeUtils"; + + public static final String FONT_KEY = "android.theme.customization.font"; + public static final String ICON_SHAPE_KEY= "android.theme.customization.adaptive_icon_shape"; + + public static final Comparator OVERLAY_INFO_COMPARATOR = + Comparator.comparingInt(a -> a.priority); + + private static ThemeUtils instance; + + private Context mContext; + private IOverlayManager mOverlayManager; + private PackageManager pm; + private Resources overlayRes; + + public ThemeUtils(Context context) { + mContext = context; + mOverlayManager = IOverlayManager.Stub + .asInterface(ServiceManager.getService(Context.OVERLAY_SERVICE)); + pm = context.getPackageManager(); + } + + public static ThemeUtils getInstance(Context context) { + if (instance == null) { + synchronized (ThemeUtils.class) { + if (instance == null) { + instance = new ThemeUtils(context); + } + } + } + return instance; + } + + public void setOverlayEnabled(String category, String packageName, String target) { + final String currentPackageName = getOverlayInfos(category, target).stream() + .filter(info -> info.isEnabled()) + .map(info -> info.packageName) + .findFirst() + .orElse(null); + + try { + if (target.equals(packageName)) { + if (currentPackageName != null) { + mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM); + } + } else { + mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM); + } + + writeSettings(category, packageName, target.equals(packageName)); + + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while setting overlay: " + e.getMessage(), e); + } + } + + public void writeSettings(String category, String packageName, boolean disable) { + final String overlayPackageJson = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, UserHandle.USER_CURRENT); + JSONObject object; + try { + if (overlayPackageJson == null) { + object = new JSONObject(); + } else { + object = new JSONObject(overlayPackageJson); + } + if (disable) { + if (object.has(category)) object.remove(category); + } else { + object.put(category, packageName); + } + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES, + object.toString(), UserHandle.USER_CURRENT); + } catch (JSONException e) { + Log.e(TAG, "Failed to parse THEME_CUSTOMIZATION_OVERLAY_PACKAGES.", e); + } + } + + public List getOverlayPackagesForCategory(String category) { + return getOverlayPackagesForCategory(category, "android"); + } + + public List getOverlayPackagesForCategory(String category, String target) { + List overlays = new ArrayList<>(); + List mPkgs = new ArrayList<>(); + overlays.add(target); + for (OverlayInfo info : getOverlayInfos(category, target)) { + if (category.equals(info.getCategory())) { + mPkgs.add(info.getPackageName()); + } + } + Collections.sort(mPkgs); + overlays.addAll(mPkgs); + return overlays; + } + + public List getOverlayInfos(String category) { + return getOverlayInfos(category, "android"); + } + + public List getOverlayInfos(String category, String target) { + final List filteredInfos = new ArrayList<>(); + try { + List overlayInfos = mOverlayManager + .getOverlayInfosForTarget(target, USER_SYSTEM); + for (OverlayInfo overlayInfo : overlayInfos) { + if (category.equals(overlayInfo.category)) { + filteredInfos.add(overlayInfo); + } + } + } catch (RemoteException re) { + Log.e(TAG, "RemoteException while getting overlay info: " + re.getMessage(), re); + } + filteredInfos.sort(OVERLAY_INFO_COMPARATOR); + return filteredInfos; + } + + public List getFonts() { + final List fontlist = new ArrayList<>(); + for (String overlayPackage : getOverlayPackagesForCategory(FONT_KEY)) { + Resources overlayRes = null; + try { + overlayRes = overlayPackage.equals("android") ? Resources.getSystem() + : pm.getResourcesForApplication(overlayPackage); + if (overlayRes != null) { + int fontId = overlayRes.getIdentifier("config_bodyFontFamily", "string", overlayPackage); + if (fontId != 0) { + String fontName = overlayRes.getString(fontId); + fontlist.add(Typeface.create(fontName, Typeface.NORMAL)); + } + } + } catch (NameNotFoundException | NotFoundException e) { + Log.e(TAG, "Error fetching fonts for package: " + overlayPackage, e); + } + } + return fontlist; + } + + public List getShapeDrawables() { + final List shapelist = new ArrayList<>(); + for (String overlayPackage : getOverlayPackagesForCategory(ICON_SHAPE_KEY)) { + shapelist.add(createShapeDrawable(overlayPackage)); + } + return shapelist; + } + + public ShapeDrawable createShapeDrawable(String overlayPackage) { + try { + if (overlayPackage.equals("android")) { + overlayRes = Resources.getSystem(); + } else { + if (overlayPackage.equals("default")) overlayPackage = "android"; + overlayRes = pm.getResourcesForApplication(overlayPackage); + } + } catch (NameNotFoundException | NotFoundException e) { + // Do nothing + } + if (overlayRes == null) { + Log.e(TAG, "Resources not found for package: " + overlayPackage); + return null; + } + final String shape = overlayRes.getString( + overlayRes.getIdentifier("config_icon_mask", + "string", overlayPackage)); + Path path = TextUtils.isEmpty(shape) ? null : PathParser.createPathFromPathData(shape); + PathShape pathShape = new PathShape(path, 100f, 100f); + ShapeDrawable shapeDrawable = new ShapeDrawable(pathShape); + int mThumbSize = (int) (mContext.getResources().getDisplayMetrics().density * 72); + shapeDrawable.setIntrinsicHeight(mThumbSize); + shapeDrawable.setIntrinsicWidth(mThumbSize); + return shapeDrawable; + } + + public boolean isOverlayEnabled(String overlayPackage) { + try { + OverlayInfo info = mOverlayManager.getOverlayInfo(overlayPackage, USER_SYSTEM); + return info == null ? false : info.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while checking if overlay is enabled: " + e.getMessage(), e); + } + return false; + } + + public boolean isDefaultOverlay(String category) { + return getOverlayPackagesForCategory(category).stream() + .noneMatch(pkg -> isOverlayEnabled(pkg)); + } + + public static String batteryTemperature(Context context, Boolean ForC) { + Intent intent = context.registerReceiver(null, new IntentFilter( + Intent.ACTION_BATTERY_CHANGED)); + float temp = ((float) (intent != null ? intent.getIntExtra( + BatteryManager.EXTRA_TEMPERATURE, 0) : 0)) / 10; + // Round up to nearest number + int c = (int) ((temp) + 0.5f); + float n = temp + 0.5f; + // Use boolean to determine celsius or fahrenheit + return String.valueOf((n - c) % 2 == 0 ? (int) temp : + ForC ? c * 9/5 + 32 + "°F" :c + "°C"); + } + + public static String getCPUTemp(Context context) { + String value = null; + String cpuTempPath = context.getResources().getString( + com.android.internal.R.string.config_cpu_temp_path); + + if (fileExists(cpuTempPath)) { + value = readOneLine(cpuTempPath); + } + + if (value == null || value.isEmpty()) { + return "N/A"; + } + + try { + int cpuTempMultiplier = context.getResources().getInteger( + com.android.internal.R.integer.config_sysCPUTempMultiplier); + + if (cpuTempMultiplier == 0) { + cpuTempMultiplier = 1; + } + + int temp = Integer.parseInt(value.trim()) / cpuTempMultiplier; + return String.format("%d°C", temp); + } catch (NumberFormatException | Resources.NotFoundException e) { + Log.w("ThemeUtils", "Failed to parse CPU temperature: " + value, e); + return "N/A"; + } + } + + public static boolean fileExists(String filename) { + if (filename == null || filename.isEmpty()) { + return false; + } + return new File(filename).exists(); + } + + public static String readOneLine(String fname) { + if (fname == null || fname.isEmpty()) { + return null; + } + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(fname), 512); + return br.readLine(); + } catch (Exception e) { + Log.w("ThemeUtils", "Failed to read file: " + fname, e); + return null; + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + // Ignore close errors + } + } + } + } +} diff --git a/core/java/com/android/internal/util/matrixx/Utils.java b/core/java/com/android/internal/util/matrixx/Utils.java new file mode 100644 index 0000000000000..a8a71c9354119 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/Utils.java @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2017-2025 crDroid Android 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.internal.util.matrixx; + +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.app.ActivityThread; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.role.RoleManager; +import android.bluetooth.BluetoothAdapter; +import android.content.ContentResolver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.om.OverlayManager; +import android.content.om.OverlayManagerTransaction; +import android.content.om.OverlayIdentifier; +import android.content.om.OverlayInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.hardware.SensorPrivacyManager; +import android.location.LocationManager; +import android.media.AudioManager; +import android.net.Uri; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.Looper; +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; + +import android.os.UserHandle; +import android.provider.Settings; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.view.IWindowManager; +import android.view.WindowManagerGlobal; +import android.widget.Toast; +import com.android.internal.R; + +import com.android.internal.notification.SystemNotificationChannels; +import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; + +import android.util.Log; + +import com.android.internal.statusbar.IStatusBarService; + +import java.util.List; + +import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; +import static android.provider.Settings.Global.ZEN_MODE_OFF; + +public class Utils { + + private static final String TAG = "Utils"; + + public static void restartApp(String appName, Context context) { + new RestartAppTask(appName, context).execute(); + } + + private static class RestartAppTask extends AsyncTask { + private Context mContext; + private String mApp; + + public RestartAppTask(String appName, Context context) { + super(); + mContext = context; + mApp = appName; + } + + @Override + protected Void doInBackground(Void... params) { + try { + ActivityManager am = + (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + IActivityManager ams = ActivityManager.getService(); + for (ActivityManager.RunningAppProcessInfo app: am.getRunningAppProcesses()) { + if (mApp.equals(app.processName)) { + ams.killApplicationProcess(app.processName, app.uid); + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } + + public static boolean isPackageInstalled(Context context, String packageName, boolean ignoreState) { + if (packageName != null) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 0); + if (!pi.applicationInfo.enabled && !ignoreState) { + return false; + } + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + return true; + } + + public static boolean isPackageInstalled(Context context, String packageName) { + return isPackageInstalled(context, packageName, true); + } + + public static boolean isPackageEnabled(Context context, String packageName) { + try { + PackageInfo pi = context.getPackageManager().getPackageInfo(packageName, 0); + return pi.applicationInfo.enabled; + } catch (PackageManager.NameNotFoundException notFound) { + return false; + } + } + + public static void switchScreenOff(Context ctx) { + PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + if (pm!= null) { + pm.goToSleep(SystemClock.uptimeMillis()); + } + } + + public static boolean deviceHasFlashlight(Context ctx) { + return ctx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH); + } + + public static boolean hasNavbarByDefault(Context context) { + boolean needsNav = context.getResources().getBoolean( + com.android.internal.R.bool.config_showNavigationBar); + String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); + if ("1".equals(navBarOverride)) { + needsNav = false; + } else if ("0".equals(navBarOverride)) { + needsNav = true; + } + return needsNav; + } + + public static void restartSystemUI() { + final IStatusBarService mBarService = IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + try { + mBarService.restartSystemUI(); + } catch (RemoteException e) { + } + } + + public static void toggleOverlay(Context context, String overlayName, boolean enable) { + OverlayManager overlayManager = context.getSystemService(OverlayManager.class); + if (overlayManager == null) { + Log.e(TAG, "OverlayManager is not available"); + return; + } + + OverlayIdentifier overlayId = getOverlayID(overlayManager, overlayName); + if (overlayId == null) { + Log.e(TAG, "Overlay ID not found for " + overlayName); + return; + } + + OverlayManagerTransaction.Builder transaction = new OverlayManagerTransaction.Builder(); + transaction.setEnabled(overlayId, enable, UserHandle.USER_CURRENT); + + try { + overlayManager.commit(transaction.build()); + } catch (Exception e) { + Log.e(TAG, "Error toggling overlay", e); + } + } + + private static OverlayIdentifier getOverlayID(OverlayManager overlayManager, String name) { + try { + if (name.contains(":")) { + String[] parts = name.split(":"); + List infos = overlayManager.getOverlayInfosForTarget(parts[0], UserHandle.CURRENT); + for (OverlayInfo info : infos) { + if (parts[1].equals(info.getOverlayName())) return info.getOverlayIdentifier(); + } + } else { + OverlayInfo info = overlayManager.getOverlayInfo(name, UserHandle.CURRENT); + if (info != null) return info.getOverlayIdentifier(); + } + } catch (Exception e) { + Log.e(TAG, "Error retrieving overlay ID", e); + } + return null; + } + + public static String getDefaultLauncher(Context context) { + final RoleManager roleManager = context.getSystemService(RoleManager.class); + final String packageName = CollectionUtils.firstOrNull( + roleManager.getRoleHolders(RoleManager.ROLE_HOME)); + return packageName != null ? packageName : ""; + } + + public static void forceStopDefaultLauncher(Context context) { + final ActivityManager activityManager = context.getSystemService(ActivityManager.class); + try { + activityManager.forceStopPackageAsUser(getDefaultLauncher(context), UserHandle.USER_CURRENT); + } catch (Exception ignored) {} + } + + public static class SleepModeController { + private final Resources mResources; + private final Context mUiContext; + + private Context mContext; + private AudioManager mAudioManager; + private NotificationManager mNotificationManager; + private WifiManager mWifiManager; + private SensorPrivacyManager mSensorPrivacyManager; + private BluetoothAdapter mBluetoothAdapter; + private int mSubscriptionId; + private Toast mToast; + + private boolean mSleepModeEnabled; + + private static boolean mWifiState; + private static boolean mCellularState; + private static boolean mBluetoothState; + private static int mRingerState; + private static int mZenState; + + private static final String TAG = "SleepModeController"; + private static final int SLEEP_NOTIFICATION_ID = 727; + public static final String SLEEP_MODE_TURN_OFF = "android.intent.action.SLEEP_MODE_TURN_OFF"; + + public SleepModeController(Context context) { + mContext = context; + mUiContext = ActivityThread.currentActivityThread().getSystemUiContext(); + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService(Context.SENSOR_PRIVACY_SERVICE); + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + mResources = mContext.getResources(); + + mSleepModeEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_ENABLED, 0, UserHandle.USER_CURRENT) == 1; + + SettingsObserver observer = new SettingsObserver(new Handler(Looper.getMainLooper())); + observer.observe(); + observer.update(); + } + + private TelephonyManager getTelephonyManager() { + int subscriptionId = mSubscriptionId; + + // If mSubscriptionId is invalid, get default data sub. + if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { + subscriptionId = SubscriptionManager.getDefaultDataSubscriptionId(); + } + + // If data sub is also invalid, get any active sub. + if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { + int[] activeSubIds = SubscriptionManager.from(mContext).getActiveSubscriptionIdList(); + if (!ArrayUtils.isEmpty(activeSubIds)) { + subscriptionId = activeSubIds[0]; + } + } + + return mContext.getSystemService( + TelephonyManager.class).createForSubscriptionId(subscriptionId); + } + + private boolean isWifiEnabled() { + if (mWifiManager == null) { + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + try { + return mWifiManager.isWifiEnabled(); + } catch (Exception e) { + return false; + } + } + + private void setWifiEnabled(boolean enable) { + if (mWifiManager == null) { + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + try { + mWifiManager.setWifiEnabled(enable); + } catch (Exception e) { + } + } + + private boolean isBluetoothEnabled() { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + try { + return mBluetoothAdapter.isEnabled(); + } catch (Exception e) { + return false; + } + } + + private void setBluetoothEnabled(boolean enable) { + if (mBluetoothAdapter == null) { + mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + } + try { + if (enable) mBluetoothAdapter.enable(); + else mBluetoothAdapter.disable(); + } catch (Exception e) { + } + } + + private boolean isSensorEnabled() { + if (mSensorPrivacyManager == null) { + mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService(Context.SENSOR_PRIVACY_SERVICE); + } + try { + return !mSensorPrivacyManager.isAllSensorPrivacyEnabled(); + } catch (Exception e) { + return false; + } + } + + private void setSensorEnabled(boolean enable) { + if (mSensorPrivacyManager == null) { + mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService(Context.SENSOR_PRIVACY_SERVICE); + } + try { + mSensorPrivacyManager.setAllSensorPrivacy(!enable); + } catch (Exception e) { + } + } + + private int getZenMode() { + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + try { + return mNotificationManager.getZenMode(); + } catch (Exception e) { + return -1; + } + } + + private void setZenMode(int mode) { + if (mNotificationManager == null) { + mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + try { + mNotificationManager.setZenMode(mode, null, TAG); + } catch (Exception e) { + } + } + + private int getRingerModeInternal() { + if (mAudioManager == null) { + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + } + try { + return mAudioManager.getRingerModeInternal(); + } catch (Exception e) { + return -1; + } + } + + private void setRingerModeInternal(int mode) { + if (mAudioManager == null) { + mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + } + try { + mAudioManager.setRingerModeInternal(mode); + } catch (Exception e) { + } + } + + private void enable() { + if (!ActivityManager.isSystemReady()) return; + + // Disable Wi-Fi + final boolean disableWifi = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_WIFI_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableWifi) { + mWifiState = isWifiEnabled(); + setWifiEnabled(false); + } + + // Disable Bluetooth + final boolean disableBluetooth = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_BLUETOOTH_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableBluetooth) { + mBluetoothState = isBluetoothEnabled(); + setBluetoothEnabled(false); + } + + // Disable Mobile Data + final boolean disableData = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_CELLULAR_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableData) { + mCellularState = getTelephonyManager().isDataEnabled(); + getTelephonyManager().setDataEnabled(false); + } + + // Disable Sensors + final boolean disableSensors = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_SENSORS_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableSensors) { + setSensorEnabled(false); + } + + // Set Ringer mode (0: Off, 1: Vibrate, 2:DND: 3:Silent) + final int ringerMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_RINGER_MODE, 0, UserHandle.USER_CURRENT); + if (ringerMode != 0) { + mRingerState = getRingerModeInternal(); + mZenState = getZenMode(); + if (ringerMode == 1) { + setRingerModeInternal(AudioManager.RINGER_MODE_VIBRATE); + setZenMode(ZEN_MODE_OFF); + } else if (ringerMode == 2) { + setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL); + setZenMode(ZEN_MODE_IMPORTANT_INTERRUPTIONS); + } else if (ringerMode == 3) { + setRingerModeInternal(AudioManager.RINGER_MODE_SILENT); + setZenMode(ZEN_MODE_OFF); + } + } + + showToast(mResources.getString(R.string.sleep_mode_enabled_toast), Toast.LENGTH_LONG); + addNotification(); + } + + private void disable() { + if (!ActivityManager.isSystemReady()) return; + + // Enable Wi-Fi + final boolean disableWifi = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_WIFI_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableWifi && mWifiState != isWifiEnabled()) { + setWifiEnabled(mWifiState); + } + + // Enable Bluetooth + final boolean disableBluetooth = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_BLUETOOTH_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableBluetooth && mBluetoothState != isBluetoothEnabled()) { + setBluetoothEnabled(mBluetoothState); + } + + // Enable Mobile Data + final boolean disableData = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_CELLULAR_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableData && mCellularState != getTelephonyManager().isDataEnabled()) { + getTelephonyManager().setDataEnabled(mCellularState); + } + + // Enable Sensors + final boolean disableSensors = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_SENSORS_TOGGLE, 1, UserHandle.USER_CURRENT) == 1; + if (disableSensors) { + setSensorEnabled(true); + try { + Thread.sleep(1000); + } catch (InterruptedException e) {} + if (!isSensorEnabled()) { + setSensorEnabled(true); + } + } + + // Set Ringer mode (0: Off, 1: Vibrate, 2:DND: 3:Silent) + final int ringerMode = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_RINGER_MODE, 0, UserHandle.USER_CURRENT); + if (ringerMode != 0 && (mRingerState != getRingerModeInternal() || + mZenState != getZenMode())) { + setRingerModeInternal(mRingerState); + setZenMode(mZenState); + } + + showToast(mResources.getString(R.string.sleep_mode_disabled_toast), Toast.LENGTH_LONG); + mNotificationManager.cancel(SLEEP_NOTIFICATION_ID); + } + + private void addNotification() { + Intent intent = new Intent(SLEEP_MODE_TURN_OFF); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + + // Display a notification + Notification.Builder builder = new Notification.Builder(mContext, SystemNotificationChannels.SLEEP) + .setTicker(mResources.getString(R.string.sleep_mode_notification_title)) + .setContentTitle(mResources.getString(R.string.sleep_mode_notification_title)) + .setContentText(mResources.getString(R.string.sleep_mode_notification_content)) + .setSmallIcon(R.drawable.ic_sleep) + .setWhen(java.lang.System.currentTimeMillis()) + .setOngoing(true) + .setContentIntent(pendingIntent) + .setAutoCancel(false); + + Notification notification = builder.build(); + mNotificationManager.notify(SLEEP_NOTIFICATION_ID, notification); + } + + private void showToast(String msg, int duration) { + Handler handler = new Handler(Looper.getMainLooper()); + handler.post(new Runnable() { + @Override + public void run() { + try { + if (mToast != null) mToast.cancel(); + mToast = Toast.makeText(mUiContext, msg, duration); + mToast.show(); + } catch (Exception e) { + } + } + }); + } + + private void setSleepMode(boolean enabled) { + if (mSleepModeEnabled == enabled) { + return; + } + + mSleepModeEnabled = enabled; + + if (mSleepModeEnabled) { + enable(); + } else { + disable(); + } + } + + class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Secure.getUriFor( + Settings.Secure.SLEEP_MODE_ENABLED), false, this, + UserHandle.USER_ALL); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + update(); + } + + void update() { + final boolean enabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.SLEEP_MODE_ENABLED, 0, UserHandle.USER_CURRENT) == 1; + setSleepMode(enabled); + } + } + } +} diff --git a/core/java/com/android/internal/util/matrixx/VibrationUtils.java b/core/java/com/android/internal/util/matrixx/VibrationUtils.java new file mode 100644 index 0000000000000..8ea7b83b33fc2 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/VibrationUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023-2024 risingOS Android 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.internal.util.matrixx; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.VibrationEffect; +import android.os.Vibrator; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class VibrationUtils { + + private static Executor executor = Executors.newSingleThreadExecutor(); + + public static void triggerVibration(final Context context, final int intensity) { + executor.execute(new Runnable() { + @Override + public void run() { + Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + if (vibrator == null || intensity == 0) { + return; + } + VibrationEffect effect = createVibrationEffect(intensity); + if (effect == null) { + return; + } + vibrator.cancel(); + vibrator.vibrate(effect); + } + }); + } + + private static VibrationEffect createVibrationEffect(int intensity) { + switch (intensity) { + case 1: + return VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK); + case 2: + return VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK); + case 3: + return VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK); + case 4: + return VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK); + case 5: + return VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK); + default: + return null; + } + } +} + diff --git a/core/java/com/android/internal/util/matrixx/cutout/CutoutFullscreenController.java b/core/java/com/android/internal/util/matrixx/cutout/CutoutFullscreenController.java new file mode 100644 index 0000000000000..81ae41774b915 --- /dev/null +++ b/core/java/com/android/internal/util/matrixx/cutout/CutoutFullscreenController.java @@ -0,0 +1,118 @@ +/** + * Copyright (C) 2018 The LineageOS project + * Copyright (C) 2019 The PixelExperience 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.internal.util.matrixx.cutout; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.text.TextUtils; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import android.provider.Settings; + +public class CutoutFullscreenController { + private Set mApps = new HashSet<>(); + private Context mContext; + + private final boolean isAvailable; + + public CutoutFullscreenController(Context context) { + mContext = context; + final Resources resources = mContext.getResources(); + + final String displayCutout = resources.getString(com.android.internal.R.string.config_mainBuiltInDisplayCutout); + isAvailable = !TextUtils.isEmpty(displayCutout); + + if (!isAvailable) { + return; + } + + SettingsObserver observer = new SettingsObserver( + new Handler(Looper.getMainLooper())); + observer.observe(); + } + + public boolean isSupported() { + return isAvailable; + } + + public boolean shouldForceCutoutFullscreen(String packageName) { + return isSupported() && mApps.contains(packageName); + } + + public Set getApps() { + return mApps; + } + + public void addApp(String packageName) { + mApps.add(packageName); + Settings.System.putString(mContext.getContentResolver(), + Settings.System.FORCE_FULLSCREEN_CUTOUT_APPS, String.join(",", mApps)); + } + + public void removeApp(String packageName) { + mApps.remove(packageName); + Settings.System.putString(mContext.getContentResolver(), + Settings.System.FORCE_FULLSCREEN_CUTOUT_APPS, String.join(",", mApps)); + } + + public void setApps(Set apps) { + mApps = apps; + } + + class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.FORCE_FULLSCREEN_CUTOUT_APPS), false, this, + UserHandle.USER_ALL); + + update(); + } + + @Override + public void onChange(boolean selfChange) { + update(); + } + + public void update() { + ContentResolver resolver = mContext.getContentResolver(); + + String apps = Settings.System.getStringForUser(resolver, + Settings.System.FORCE_FULLSCREEN_CUTOUT_APPS, + UserHandle.USER_CURRENT); + if (apps != null) { + setApps(new HashSet<>(Arrays.asList(apps.split(",")))); + } else { + setApps(new HashSet<>()); + } + } + } +} diff --git a/core/java/com/android/internal/widget/BigPictureNotificationImageView.java b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java index 3f3b513eff509..1c428ff0228d1 100644 --- a/core/java/com/android/internal/widget/BigPictureNotificationImageView.java +++ b/core/java/com/android/internal/widget/BigPictureNotificationImageView.java @@ -66,7 +66,7 @@ public BigPictureNotificationImageView(@NonNull Context context, @Nullable Attri public BigPictureNotificationImageView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - boolean isLowRam = ActivityManager.isLowRamDeviceStatic(); + boolean isLowRam = true; mMaximumDrawableWidth = context.getResources().getDimensionPixelSize( isLowRam ? R.dimen.notification_big_picture_max_width_low_ram : R.dimen.notification_big_picture_max_width); diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index 6351c0e631ac7..97e66d9ddfd06 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -34,6 +34,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; +import java.util.Locale; /** A class to extract Drawables from a MessagingStyle/ConversationStyle message. */ public class LocalImageResolver { @@ -259,6 +260,28 @@ private static void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo int maxWidth, int maxHeight) { final Size size = info.getSize(); + final String mimeType = info.getMimeType(); + boolean isAllowedCodec = false; + if (mimeType != null) { + switch (mimeType.toLowerCase(Locale.US)) { + case "image/png": + case "image/jpeg": + case "image/webp": + case "image/gif": + case "image/bmp": + case "image/x-ico": + case "image/vnd.wap.wbmp": + case "image/heif": + case "image/heic": + case "image/avif": + isAllowedCodec = true; + break; + } + } + if (!isAllowedCodec) { + throw new RuntimeException("Image mime type (" + mimeType + ") is not allowed."); + } + if (size.getWidth() > DEFAULT_DECODE_HARD_LIMIT_PX || size.getHeight() > DEFAULT_DECODE_HARD_LIMIT_PX) { // The image is larger than what we can reasonably expect to decode without filling up diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 842404753fb8d..ff58e9b992f2c 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -128,7 +128,7 @@ public class LockPatternUtils { public static final int PIN_LENGTH_UNAVAILABLE = -1; // This is the minimum pin length at which auto confirmation is supported - public static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 6; + public static final int MIN_AUTO_PIN_REQUIREMENT_LENGTH = 4; /** * Header used for the encryption and decryption of the device credential for diff --git a/core/java/com/android/server/LocalServices.java b/core/java/com/android/server/LocalServices.java index 9c0fe03dd1cae..fec0147e821df 100644 --- a/core/java/com/android/server/LocalServices.java +++ b/core/java/com/android/server/LocalServices.java @@ -18,7 +18,7 @@ import com.android.internal.annotations.VisibleForTesting; -import android.util.ArrayMap; +import java.util.HashMap; /** * This class is used in a similar way as ServiceManager, except the services registered here @@ -33,8 +33,8 @@ public final class LocalServices { private LocalServices() {} - private static final ArrayMap, Object> sLocalServiceObjects = - new ArrayMap, Object>(); + private static final HashMap, Object> sLocalServiceObjects = + new HashMap, Object>(); /** * Returns a local service instance that implements the specified interface. diff --git a/core/java/com/oplus/theme/OplusThemeUtil.java b/core/java/com/oplus/theme/OplusThemeUtil.java new file mode 100644 index 0000000000000..cea1cfd31b834 --- /dev/null +++ b/core/java/com/oplus/theme/OplusThemeUtil.java @@ -0,0 +1,9 @@ +package com.oplus.theme; + +import android.compat.annotation.UnsupportedAppUsage; + +public class OplusThemeUtil { + /** @hide */ + @UnsupportedAppUsage + public static String CUSTOM_THEME_PATH = "/data/theme/com.oplus.camera"; +} diff --git a/core/java/com/oplus/util/OplusTypeCastingHelper.java b/core/java/com/oplus/util/OplusTypeCastingHelper.java new file mode 100644 index 0000000000000..4819e9f20b720 --- /dev/null +++ b/core/java/com/oplus/util/OplusTypeCastingHelper.java @@ -0,0 +1,10 @@ +package com.oplus.util; + +public final class OplusTypeCastingHelper { + public static T typeCasting(Class type, Object object) { + if (object != null && type.isInstance(object)) { + return type.cast(object); + } + return null; + } +} diff --git a/core/java/org/derpfest/display/IRefreshRateListener.aidl b/core/java/org/derpfest/display/IRefreshRateListener.aidl new file mode 100644 index 0000000000000..4a14c48d9d8d4 --- /dev/null +++ b/core/java/org/derpfest/display/IRefreshRateListener.aidl @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023-2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.derpfest.display; + +/** @hide */ +oneway interface IRefreshRateListener { + + void onRequestedRefreshRate(int refreshRate); + + void onRequestedMemcRefreshRate(int refreshRate); +} diff --git a/core/java/org/derpfest/display/IRefreshRateManagerService.aidl b/core/java/org/derpfest/display/IRefreshRateManagerService.aidl new file mode 100644 index 0000000000000..39a94d7e0413d --- /dev/null +++ b/core/java/org/derpfest/display/IRefreshRateManagerService.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023-2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.derpfest.display; + +import org.derpfest.display.IRefreshRateListener; + +/** @hide */ +interface IRefreshRateManagerService { + + /* Request MEMC required refresh rate in video apps */ + void requestMemcRefreshRate(in int refreshRate); + + /* Restore refresh rate after exiting MEMC mode */ + void clearRequestedMemcRefreshRate(); + + /* Get user preferred refresh rate for specific package, return -1 if not set */ + int getRefreshRateForPackage(in String packageName); + + /* Request user preferred refresh rate for specific package */ + void setRefreshRateForPackage(in String packageName, in int refreshRate); + + /* Reset user preferred refresh rate for specific package (Follow system) */ + void unsetRefreshRateForPackage(in String packageName); + + /* Force highest refresh rate in every apps, unless MEMC is running */ + void setExtremeRefreshRateEnabled(in boolean enabled); + + /* Get user preferred refresh in current app, return -1 if not set */ + int getRequestedRefreshRate(); + + /* Get current MEMC requested refresh rate, return -1 if not set */ + int getRequestedMemcRefreshRate(); + + /* Register listener to listen requested refresh rate change */ + boolean registerRefreshRateListener(in IRefreshRateListener listener); + + /* Unregister listener to listen requested refresh rate change */ + boolean unregisterRefreshRateListener(in IRefreshRateListener listener); +} diff --git a/core/java/org/derpfest/display/RefreshRateManager.java b/core/java/org/derpfest/display/RefreshRateManager.java new file mode 100644 index 0000000000000..38e26f9b85c89 --- /dev/null +++ b/core/java/org/derpfest/display/RefreshRateManager.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2023-2024 The Nameless-AOSP Project + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.derpfest.display; + +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.util.matrixx.Utils; +import com.android.internal.util.matrixx.DisplayRefreshRateHelper; + +/** @hide */ +@SystemService(Context.REFRESH_RATE_MANAGER_SERVICE) +public class RefreshRateManager { + + private static final String TAG = "RefreshRateManager"; + + private final Context mContext; + private final DisplayRefreshRateHelper mDisplayRefreshRateHelper; + private final IRefreshRateManagerService mService; + + public RefreshRateManager(Context context, IRefreshRateManagerService service) { + mContext = context; + mService = service; + mDisplayRefreshRateHelper = DisplayRefreshRateHelper.getInstance(context); + } + + public void requestMemcRefreshRate(int refreshRate) { + if (mService == null) { + Slog.e(TAG, "Failed to request memc refresh rate. Service is null"); + return; + } + if (refreshRate > 0f && + !mDisplayRefreshRateHelper.isRefreshRateValid(refreshRate)) { + Slog.e(TAG, "Failed to request memc refresh rate. Invalid refresh rate"); + return; + } + try { + mService.requestMemcRefreshRate(refreshRate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void clearRequestedMemcRefreshRate() { + if (mService == null) { + Slog.e(TAG, "Failed to clear memc refresh rate. Service is null"); + return; + } + try { + mService.clearRequestedMemcRefreshRate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public int getRefreshRateForPackage(String packageName) { + if (mService == null) { + Slog.e(TAG, "Failed to get refresh rate for package. Service is null"); + return -1; + } + if (!Utils.isPackageInstalled(mContext, packageName)) { + Slog.e(TAG, "Failed to get refresh rate for package. Package " + packageName + " is unavailable"); + return -1; + } + try { + return mService.getRefreshRateForPackage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void setRefreshRateForPackage(String packageName, int refreshRate) { + if (mService == null) { + Slog.e(TAG, "Failed to set refresh rate for package. Service is null"); + return; + } + if (!Utils.isPackageInstalled(mContext, packageName)) { + Slog.e(TAG, "Failed to set refresh rate for package. Package " + packageName + " is unavailable"); + return; + } + if (refreshRate > 0f && + !mDisplayRefreshRateHelper.isRefreshRateValid(refreshRate)) { + Slog.e(TAG, "Failed to set refresh rate for package. Invalid refresh rate"); + return; + } + try { + mService.setRefreshRateForPackage(packageName, refreshRate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void unsetRefreshRateForPackage(String packageName) { + if (mService == null) { + Slog.e(TAG, "Failed to unset refresh rate for package. Service is null"); + return; + } + if (!Utils.isPackageInstalled(mContext, packageName)) { + Slog.e(TAG, "Failed to unset refresh rate for package. Package " + packageName + " is unavailable"); + return; + } + try { + mService.unsetRefreshRateForPackage(packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public void setExtremeRefreshRateEnabled(boolean enabled) { + if (mService == null) { + Slog.e(TAG, "Failed to set extreme refresh rate. Service is null"); + return; + } + try { + mService.setExtremeRefreshRateEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public int getRequestedRefreshRate() { + if (mService == null) { + Slog.e(TAG, "Failed to get requested refresh rate. Service is null"); + return -1; + } + try { + return mService.getRequestedRefreshRate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public int getRequestedMemcRefreshRate() { + if (mService == null) { + Slog.e(TAG, "Failed to get requested memc refresh rate. Service is null"); + return -1; + } + try { + return mService.getRequestedMemcRefreshRate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public boolean registerRefreshRateListener(IRefreshRateListener.Stub listener) { + if (mService == null) { + Slog.e(TAG, "Failed to register refresh rate listener. Service is null"); + return false; + } + try { + return mService.registerRefreshRateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public boolean unregisterRefreshRateListener(IRefreshRateListener.Stub listener) { + if (mService == null) { + Slog.e(TAG, "Failed to unregister refresh rate listener. Service is null"); + return false; + } + try { + return mService.unregisterRefreshRateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index eb3d539c9a98c..99fa0928417d6 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -70,6 +70,18 @@ struct fields_t { jmethodID rect_constructor; jmethodID face_constructor; jmethodID point_constructor; + jfieldID face_sm_degree; + jfieldID face_sm_score; + jfieldID face_blink_detected; + jfieldID face_gaze_angle; + jfieldID face_updown_dir; + jfieldID face_leftright_dir; + jfieldID face_roll_dir; + jfieldID face_leye_blink; + jfieldID face_reye_blink; + jfieldID face_left_right_gaze; + jfieldID face_top_bottom_gaze; + jfieldID face_recognised; }; static fields_t fields; @@ -108,6 +120,7 @@ class JNICameraContext: public CameraListener jclass mFaceClass; // strong reference to Face class jclass mRectClass; // strong reference to Rect class jclass mPointClass; // strong reference to Point class + bool mIsExtendedFace; Mutex mLock; /* @@ -159,8 +172,16 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, mCameraJClass = (jclass)env->NewGlobalRef(clazz); mCamera = camera; - jclass faceClazz = env->FindClass("android/hardware/Camera$Face"); - mFaceClass = (jclass) env->NewGlobalRef(faceClazz); + jclass extendedfaceClazz = env->FindClass("com/qualcomm/qti/camera/ExtendedFace"); + if (NULL != extendedfaceClazz) { + mFaceClass = (jclass) env->NewGlobalRef(extendedfaceClazz); + mIsExtendedFace = true; + } else { + env->ExceptionClear(); + jclass faceClazz = env->FindClass("android/hardware/Camera$Face"); + mFaceClass = (jclass) env->NewGlobalRef(faceClazz); + mIsExtendedFace = false; + } jclass rectClazz = env->FindClass("android/graphics/Rect"); mRectClass = (jclass) env->NewGlobalRef(rectClazz); @@ -412,7 +433,6 @@ void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_m env->SetIntField(rect, fields.rect_top, metadata->faces[i].rect[1]); env->SetIntField(rect, fields.rect_right, metadata->faces[i].rect[2]); env->SetIntField(rect, fields.rect_bottom, metadata->faces[i].rect[3]); - env->SetObjectField(face, fields.face_rect, rect); env->SetIntField(face, fields.face_score, metadata->faces[i].score); @@ -441,6 +461,21 @@ void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_m env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]); env->SetObjectField(face, fields.face_mouth, mouth); env->DeleteLocalRef(mouth); + + if (mIsExtendedFace) { + env->SetIntField(face, fields.face_sm_degree, metadata->faces[i].smile_degree); + env->SetIntField(face, fields.face_sm_score, metadata->faces[i].smile_score); + env->SetIntField(face, fields.face_blink_detected, metadata->faces[i].blink_detected); + env->SetIntField(face, fields.face_recognised, metadata->faces[i].face_recognised); + env->SetIntField(face, fields.face_gaze_angle, metadata->faces[i].gaze_angle); + env->SetIntField(face, fields.face_updown_dir, metadata->faces[i].updown_dir); + env->SetIntField(face, fields.face_leftright_dir, metadata->faces[i].leftright_dir); + env->SetIntField(face, fields.face_roll_dir, metadata->faces[i].roll_dir); + env->SetIntField(face, fields.face_leye_blink, metadata->faces[i].leye_blink); + env->SetIntField(face, fields.face_reye_blink, metadata->faces[i].reye_blink); + env->SetIntField(face, fields.face_left_right_gaze, metadata->faces[i].left_right_gaze); + env->SetIntField(face, fields.face_top_bottom_gaze, metadata->faces[i].top_bottom_gaze); + } } env->DeleteLocalRef(face); @@ -478,6 +513,56 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM } } +static void android_hardware_Camera_setLongshot(JNIEnv *env, jobject thiz, jboolean enable) +{ + ALOGV("setLongshot"); + JNICameraContext* context; + status_t rc; + sp camera = get_native_camera(env, thiz, &context); + if (camera == 0) return; + + if ( enable ) { + rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_ON, 0, 0); + } else { + rc = camera->sendCommand(CAMERA_CMD_LONGSHOT_OFF, 0, 0); + } + + if (rc != NO_ERROR) { + jniThrowException(env, "java/lang/RuntimeException", "enabling longshot mode failed"); + } +} + +static void android_hardware_Camera_sendHistogramData(JNIEnv *env, jobject thiz) + { + ALOGV("sendHistogramData" ); + JNICameraContext* context; + status_t rc; + sp camera = get_native_camera(env, thiz, &context); + if (camera == 0) return; + + rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_SEND_DATA, 0, 0); + + if (rc != NO_ERROR) { + jniThrowException(env, "java/lang/RuntimeException", "send histogram data failed"); + } + } + static void android_hardware_Camera_setHistogramMode(JNIEnv *env, jobject thiz, jboolean mode) + { + ALOGV("setHistogramMode: mode:%d", (int)mode); + JNICameraContext* context; + status_t rc; + sp camera = get_native_camera(env, thiz, &context); + if (camera == 0) return; + + if(mode == true) + rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_ON, 0, 0); + else + rc = camera->sendCommand(CAMERA_CMD_HISTOGRAM_OFF, 0, 0); + + if (rc != NO_ERROR) { + jniThrowException(env, "java/lang/RuntimeException", "set histogram mode failed"); + } + } void JNICameraContext::addCallbackBuffer( JNIEnv *env, jbyteArray cbb, int msgType) { @@ -868,7 +953,25 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t context->setCallbackMode(env, installed, manualBuffer); } -static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, jint msgType) { +static void android_hardware_Camera_setMetadataCb(JNIEnv *env, jobject thiz, jboolean mode) +{ + ALOGV("setMetadataCb: mode:%d", (int)mode); + JNICameraContext* context; + status_t rc; + sp camera = get_native_camera(env, thiz, &context); + if (camera == 0) return; + + if(mode == true) + rc = camera->sendCommand(CAMERA_CMD_METADATA_ON, 0, 0); + else + rc = camera->sendCommand(CAMERA_CMD_METADATA_OFF, 0, 0); + + if (rc != NO_ERROR) { + jniThrowException(env, "java/lang/RuntimeException", "set metadata mode failed"); + } +} + +static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) { ALOGV("addCallbackBuffer: 0x%x", msgType); JNICameraContext* context = reinterpret_cast(env->GetLongField(thiz, fields.context)); @@ -1133,6 +1236,18 @@ static int32_t android_hardware_Camera_getAudioRestriction( return ret; } +static void android_hardware_Camera_sendVendorCommand(JNIEnv *env, jobject thiz, + jint cmd, jint arg1, jint arg2) +{ + ALOGV("sendVendorCommand"); + sp camera = get_native_camera(env, thiz, NULL); + if (camera == 0) return; + + if (camera->sendCommand(cmd, arg1, arg2) != NO_ERROR) { + jniThrowRuntimeException(env, "sending vendor command failed"); + } +} + //------------------------------------------------- static const JNINativeMethod camMethods[] = { @@ -1158,6 +1273,10 @@ static const JNINativeMethod camMethods[] = { {"native_autoFocus", "()V", (void *)android_hardware_Camera_autoFocus}, {"native_cancelAutoFocus", "()V", (void *)android_hardware_Camera_cancelAutoFocus}, {"native_takePicture", "(I)V", (void *)android_hardware_Camera_takePicture}, + { "native_setHistogramMode", "(Z)V", (void *)android_hardware_Camera_setHistogramMode }, + { "native_setMetadataCb", "(Z)V", (void *)android_hardware_Camera_setMetadataCb }, + { "native_sendHistogramData", "()V", (void *)android_hardware_Camera_sendHistogramData }, + { "native_setLongshot", "(Z)V", (void *)android_hardware_Camera_setLongshot }, {"native_setParameters", "(Ljava/lang/String;)V", (void *)android_hardware_Camera_setParameters}, {"native_getParameters", "()Ljava/lang/String;", @@ -1175,6 +1294,7 @@ static const JNINativeMethod camMethods[] = { (void *)android_hardware_Camera_enableFocusMoveCallback}, {"setAudioRestriction", "(I)V", (void *)android_hardware_Camera_setAudioRestriction}, {"getAudioRestriction", "()I", (void *)android_hardware_Camera_getAudioRestriction}, + {"_sendVendorCommand", "(III)V", (void *)android_hardware_Camera_sendVendorCommand}, }; struct field { @@ -1217,6 +1337,27 @@ int register_android_hardware_Camera(JNIEnv *env) { "android/graphics/Point", "y", "I", &fields.point_y}, }; + field extendedfacefields_to_find[] = { + { "com/qualcomm/qti/camera/ExtendedFace", "rect", "Landroid/graphics/Rect;", &fields.face_rect }, + { "com/qualcomm/qti/camera/ExtendedFace", "score", "I", &fields.face_score }, + { "com/qualcomm/qti/camera/ExtendedFace", "id", "I", &fields.face_id }, + { "com/qualcomm/qti/camera/ExtendedFace", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye }, + { "com/qualcomm/qti/camera/ExtendedFace", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye }, + { "com/qualcomm/qti/camera/ExtendedFace", "mouth", "Landroid/graphics/Point;", &fields.face_mouth }, + { "com/qualcomm/qti/camera/ExtendedFace", "smileDegree", "I", &fields.face_sm_degree }, + { "com/qualcomm/qti/camera/ExtendedFace", "smileScore", "I", &fields.face_sm_score }, + { "com/qualcomm/qti/camera/ExtendedFace", "blinkDetected", "I", &fields.face_blink_detected }, + { "com/qualcomm/qti/camera/ExtendedFace", "faceRecognized", "I", &fields.face_recognised }, + { "com/qualcomm/qti/camera/ExtendedFace", "gazeAngle", "I", &fields.face_gaze_angle }, + { "com/qualcomm/qti/camera/ExtendedFace", "updownDir", "I", &fields.face_updown_dir }, + { "com/qualcomm/qti/camera/ExtendedFace", "leftrightDir", "I", &fields.face_leftright_dir }, + { "com/qualcomm/qti/camera/ExtendedFace", "rollDir", "I", &fields.face_roll_dir }, + { "com/qualcomm/qti/camera/ExtendedFace", "leyeBlink", "I", &fields.face_leye_blink }, + { "com/qualcomm/qti/camera/ExtendedFace", "reyeBlink", "I", &fields.face_reye_blink }, + { "com/qualcomm/qti/camera/ExtendedFace", "leftrightGaze", "I", &fields.face_left_right_gaze }, + { "com/qualcomm/qti/camera/ExtendedFace", "topbottomGaze", "I", &fields.face_top_bottom_gaze }, + }; + find_fields(env, fields_to_find, NELEM(fields_to_find)); jclass clazz = FindClassOrDie(env, "android/hardware/Camera"); @@ -1236,6 +1377,14 @@ int register_android_hardware_Camera(JNIEnv *env) return -1; } + clazz = env->FindClass("com/qualcomm/qti/camera/ExtendedFace"); + if (NULL != clazz) { + fields.face_constructor = env->GetMethodID(clazz, "", "()V"); + find_fields(env, extendedfacefields_to_find, NELEM(extendedfacefields_to_find)); + } else { + env->ExceptionClear(); + } + // Register native functions return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods)); } diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp index 828f2eb76c60b..f7d4e4cc2b8c0 100644 --- a/core/jni/android_hardware_camera2_DngCreator.cpp +++ b/core/jni/android_hardware_camera2_DngCreator.cpp @@ -1514,6 +1514,19 @@ static sp DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image writer); } + // MIUI ADD START + { + // market name + // Use "" to represent unknown productname as suggested in XiaoMi spec. + std::string productname = GetProperty("ro.product.marketname", ""); + uint32_t count = static_cast(productname.size()) + 1; + + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_XIAOMI_PRODUCT, count, + reinterpret_cast(productname.c_str()), TIFF_IFD_0), env, TAG_XIAOMI_PRODUCT, + writer); + } + // END + { // x resolution uint32_t xres[] = { 72, 1 }; // default 72 ppi @@ -1660,6 +1673,38 @@ static sp DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image TIFF_IFD_0), env, TAG_FOCALLENGTH, writer); } + { + // FocalLengthIn35mmFilm + uint16_t focalLengthIn35mmFilm = 0; + uint32_t tag = 0; + sp vTags; + sp cache = VendorTagDescriptorCache::getGlobalVendorTagCache(); + if (cache) { + auto vendorId = results.getVendorId(); + cache->getVendorTagDescriptor(vendorId, &vTags); + } + + if (vTags != NULL) { + const char *section = "com.xiaomi.sensor.info"; + const char *TagName = "focalLength35mm"; + const String8 sectionName(section); + const String8 tagName(TagName); + status_t ret = vTags->lookupTag(tagName, sectionName, &tag); + if (ret == 0) { + camera_metadata_entry entry = results.find(tag); + if (entry.count != 0) { + focalLengthIn35mmFilm =static_cast (entry.data.f[0] + 0.5f); + BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_FOCALLLENGTHIN35MMFILM, 1, &focalLengthIn35mmFilm, + TIFF_IFD_0), env, TAG_FOCALLLENGTHIN35MMFILM, writer); + } else { + ALOGW("%s: get focalLength35mm failed.", __FUNCTION__); + } + } + } else { + ALOGW("%s:com.xiaomi.sensor.info.focalLength35mm vTags is null.", __FUNCTION__); + } + } + { // f number camera_metadata_entry entry = diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index efd279b3b244f..afdde0c8c438f 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,9 @@ static jmethodID gIntegerCstor; static jclass gMapClass; static jmethodID gMapPut; +static jclass gAppVolumeClass; +static jmethodID gAppVolumeCstor; + static jclass gAudioHandleClass; static jmethodID gAudioHandleCstor; static struct { @@ -962,6 +966,88 @@ android_media_AudioSystem_getMasterBalance(JNIEnv *env, jobject thiz) return balance; } +static jint +android_media_AudioSystem_setAppVolume(JNIEnv *env, jobject thiz, jstring packageName, jfloat value) +{ + const jchar* c_packageName = env->GetStringCritical(packageName, 0); + String8 package8 = String8(reinterpret_cast(c_packageName), env->GetStringLength(packageName)); + env->ReleaseStringCritical(packageName, c_packageName); + return (jint) check_AudioSystem_Command(AudioSystem::setAppVolume(package8, value)); +} + +static jint +android_media_AudioSystem_setAppMute(JNIEnv *env, jobject thiz, jstring packageName, jboolean mute) +{ + const jchar* c_packageName = env->GetStringCritical(packageName, 0); + String8 package8 = String8(reinterpret_cast(c_packageName), env->GetStringLength(packageName)); + env->ReleaseStringCritical(packageName, c_packageName); + return (jint) check_AudioSystem_Command(AudioSystem::setAppMute(package8, mute)); +} + +jint convertAppVolumeFromNative(JNIEnv *env, jobject *jAppVolume, const media::AppVolume *AppVolume) +{ + jint jStatus = (jint)AUDIO_JAVA_SUCCESS; + jstring jPackageName; + jfloat jVolume; + jboolean jMute; + jboolean jActive; + + if (AppVolume == NULL || jAppVolume == NULL) { + jStatus = (jint)AUDIO_JAVA_ERROR; + goto exit; + } + + jPackageName = env->NewStringUTF(AppVolume->packageName); + jVolume = AppVolume->volume; + jMute = AppVolume->muted; + jActive = AppVolume->active; + + *jAppVolume = env->NewObject(gAppVolumeClass, gAppVolumeCstor, + jPackageName, jMute, jVolume, jActive); + + env->DeleteLocalRef(jPackageName); +exit: + return jStatus; +} + +static jint +android_media_AudioSystem_listAppVolumes(JNIEnv *env, jobject clazz, jobject jVolumes) +{ + ALOGV("listAppVolumes"); + + if (jVolumes == NULL) { + ALOGE("listAppVolumes NULL AppVolume ArrayList"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + if (!env->IsInstanceOf(jVolumes, gArrayListClass)) { + ALOGE("listAppVolumes not an arraylist"); + return (jint)AUDIO_JAVA_BAD_VALUE; + } + + std::vector volumes; + + jint jStatus = (jint)AUDIO_JAVA_SUCCESS; + status_t status = AudioSystem::listAppVolumes(&volumes); + + if (status != NO_ERROR) { + ALOGE("AudioSystem::listAppVolumes error %d", status); + jStatus = nativeToJavaStatus(status); + return jStatus; + } + + for (size_t i = 0; i < volumes.size(); i++) { + jobject jAppVolume; + jStatus = convertAppVolumeFromNative(env, &jAppVolume, &volumes[i]); + if (jStatus != AUDIO_JAVA_SUCCESS) { + return jStatus; + } + env->CallBooleanMethod(jVolumes, gArrayListMethods.add, jAppVolume); + env->DeleteLocalRef(jAppVolume); + } + + return jStatus; +} + static jint android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz) { @@ -3696,6 +3782,13 @@ static const JNINativeMethod gMethods[] = { android_media_AudioSystem_listenForSystemPropertyChange), MAKE_JNI_NATIVE_METHOD("triggerSystemPropertyUpdate", "(J)V", android_media_AudioSystem_triggerSystemPropertyUpdate), + + MAKE_JNI_NATIVE_METHOD("setAppVolume", "(Ljava/lang/String;F)I", + android_media_AudioSystem_setAppVolume), + MAKE_JNI_NATIVE_METHOD("setAppMute", "(Ljava/lang/String;Z)I", + android_media_AudioSystem_setAppMute), + MAKE_JNI_NATIVE_METHOD("listAppVolumes", "(Ljava/util/ArrayList;)I", + android_media_AudioSystem_listAppVolumes), MAKE_AUDIO_SYSTEM_METHOD(setSimulateDeviceConnections), }; @@ -3978,6 +4071,11 @@ int register_android_media_AudioSystem(JNIEnv *env) LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&gVm) != 0); + jclass AppVolumeClass = FindClassOrDie(env, "android/media/AppVolume"); + gAppVolumeClass = MakeGlobalRefOrDie(env, AppVolumeClass); + gAppVolumeCstor = GetMethodIDOrDie(env, AppVolumeClass, "", + "(Ljava/lang/String;ZFZ)V"); + AudioSystem::addErrorCallback(android_media_AudioSystem_error_callback); RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp index 0a5e786175682..2e9aa3405dac2 100644 --- a/core/jni/android_util_EventLog.cpp +++ b/core/jni/android_util_EventLog.cpp @@ -68,16 +68,16 @@ static void android_util_EventLog_readEventsOnWrapping(JNIEnv* env, jobject claz */ static const JNINativeMethod gRegisterMethods[] = { /* name, signature, funcPtr */ - { "writeEvent", "(II)I", (void*) ELog::writeEventInteger }, - { "writeEvent", "(IJ)I", (void*) ELog::writeEventLong }, - { "writeEvent", "(IF)I", (void*) ELog::writeEventFloat }, - { "writeEvent", "(ILjava/lang/String;)I", (void*) ELog::writeEventString }, - { "writeEvent", "(I[Ljava/lang/Object;)I", (void*) ELog::writeEventArray }, - { "readEvents", + { "nativeWriteEvent", "(II)I", (void*) ELog::writeEventInteger }, + { "nativeWriteEvent", "(IJ)I", (void*) ELog::writeEventLong }, + { "nativeWriteEvent", "(IF)I", (void*) ELog::writeEventFloat }, + { "nativeWriteEvent", "(ILjava/lang/String;)I", (void*) ELog::writeEventString }, + { "nativeWriteEvent", "(I[Ljava/lang/Object;)I", (void*) ELog::writeEventArray }, + { "nativeReadEvents", "([ILjava/util/Collection;)V", (void*) android_util_EventLog_readEvents }, - { "readEventsOnWrapping", + { "nativeReadEventsOnWrapping", "([IJLjava/util/Collection;)V", (void*) android_util_EventLog_readEventsOnWrapping }, diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index fe69dd9a21b27..74c35777afe48 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -551,12 +551,7 @@ void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz, #if defined(__linux__) struct sched_param param; param.sched_priority = pri; - int rc = sched_setscheduler(tid, policy, ¶m); - if (rc) { - signalExceptionForPriorityError(env, errno, tid); - } -#else - signalExceptionForPriorityError(env, ENOSYS, tid); + sched_setscheduler(tid, policy, ¶m); #endif } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 769c3d3110dff..0ca79769c40cf 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -831,6 +831,7 @@ + @@ -869,6 +870,9 @@ + + + @@ -949,6 +953,10 @@ android:knownCerts="@array/config_setContactsDefaultAccountKnownSigners" android:featureFlag="android.provider.new_default_account_api_enabled"/> + + + @@ -9495,6 +9503,8 @@ + + diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml index a6710490d820d..10ac35fb21730 100644 --- a/core/res/res/anim/activity_close_exit.xml +++ b/core/res/res/anim/activity_close_exit.xml @@ -18,6 +18,7 @@ --> + android:lStar="4" android:alpha="0.56"/> diff --git a/core/res/res/color/config_progress_background_tint.xml b/core/res/res/color/config_progress_background_tint.xml index b086e20bf1619..dfc914e76c8d0 100644 --- a/core/res/res/color/config_progress_background_tint.xml +++ b/core/res/res/color/config_progress_background_tint.xml @@ -15,5 +15,5 @@ --> - + diff --git a/core/res/res/drawable/color_surface_alpha_toast.xml b/core/res/res/drawable/color_surface_alpha_toast.xml new file mode 100644 index 0000000000000..7858cbd2620e9 --- /dev/null +++ b/core/res/res/drawable/color_surface_alpha_toast.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_link.xml b/core/res/res/drawable/ic_link.xml new file mode 100644 index 0000000000000..97322a4f24bdf --- /dev/null +++ b/core/res/res/drawable/ic_link.xml @@ -0,0 +1,9 @@ + + + diff --git a/core/res/res/drawable/ic_sleep.xml b/core/res/res/drawable/ic_sleep.xml new file mode 100644 index 0000000000000..1dddd7baf35e5 --- /dev/null +++ b/core/res/res/drawable/ic_sleep.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/core/res/res/drawable/ic_zen_priority_modes.xml b/core/res/res/drawable/ic_zen_priority_modes.xml index 7412ef0ab3879..295a42118e178 100644 --- a/core/res/res/drawable/ic_zen_priority_modes.xml +++ b/core/res/res/drawable/ic_zen_priority_modes.xml @@ -19,7 +19,8 @@ Copyright (C) 2024 The Android Open Source Project android:viewportWidth="960" android:viewportHeight="960" android:tint="?android:attr/colorControlNormal"> - - \ No newline at end of file + + diff --git a/core/res/res/drawable/pocket_mode_illustration.xml b/core/res/res/drawable/pocket_mode_illustration.xml new file mode 100644 index 0000000000000..3b55a10cbaf60 --- /dev/null +++ b/core/res/res/drawable/pocket_mode_illustration.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/core/res/res/drawable/popup_background_material.xml b/core/res/res/drawable/popup_background_material.xml index 9ad7bfc68122b..5910b9f163a51 100644 --- a/core/res/res/drawable/popup_background_material.xml +++ b/core/res/res/drawable/popup_background_material.xml @@ -18,7 +18,7 @@ android:shape="rectangle"> + android:radius="?attr/dialogCornerRadius" /> diff --git a/core/res/res/drawable/sym_def_app_icon_background.xml b/core/res/res/drawable/sym_def_app_icon_background.xml index fa5cbd9d504be..17b592fe10f3c 100644 --- a/core/res/res/drawable/sym_def_app_icon_background.xml +++ b/core/res/res/drawable/sym_def_app_icon_background.xml @@ -1,14 +1,52 @@ - - - + android:width="108dp" + android:viewportHeight="108.0" + android:viewportWidth="108.0" + xmlns:android="http://schemas.android.com/apk/res/android"> + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/drawable/sym_def_app_icon_foreground.xml b/core/res/res/drawable/sym_def_app_icon_foreground.xml index 68cf7c93bca51..0a5a334d10f72 100644 --- a/core/res/res/drawable/sym_def_app_icon_foreground.xml +++ b/core/res/res/drawable/sym_def_app_icon_foreground.xml @@ -1,7 +1,17 @@ - - - - - - - - - - + android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z"> + + + + + + - + diff --git a/core/res/res/drawable/toast_frame.xml b/core/res/res/drawable/toast_frame.xml index 34987394b2ece..be1fdcc9c35ea 100644 --- a/core/res/res/drawable/toast_frame.xml +++ b/core/res/res/drawable/toast_frame.xml @@ -17,7 +17,7 @@ --> - + diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml index 178505c264a46..b1510fdcb93dd 100644 --- a/core/res/res/layout/alert_dialog_material.xml +++ b/core/res/res/layout/alert_dialog_material.xml @@ -54,7 +54,7 @@ android:layout_height="wrap_content" android:paddingEnd="?attr/dialogPreferredPadding" android:paddingStart="?attr/dialogPreferredPadding" - style="@style/TextAppearance.Material.Subhead" /> + style="@style/TextAppearance.DeviceDefault.Subhead" /> +