diff --git a/Android.bp b/Android.bp index e5d37ab03960..305174d5883d 100644 --- a/Android.bp +++ b/Android.bp @@ -255,6 +255,7 @@ filegroup { ":framework_native_aidl", ":gatekeeper_aidl", ":gsiservice_aidl", + ":guiconstants_aidl", ":incidentcompanion_aidl", ":installd_aidl", ":keystore_aidl", diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java index e15f0f37fc62..0e98bf0e8e00 100644 --- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java +++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java @@ -146,6 +146,8 @@ void restrictApp(@NonNull String packageName, int userId, void setActiveAdminApps(Set adminPkgs, int userId); + void setAdminProtectedPackages(Set packageNames, int userId); + void onAdminDataAvailable(); void clearCarrierPrivilegedApps(); diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index 2f5f555817ec..146d68fdd653 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -687,6 +687,10 @@ public void run() { } } catch (XmlPullParserException | IOException e) { Slog.wtf(TAG, "Error jobstore xml.", e); + } catch (Exception e) { + // Crashing at this point would result in a boot loop, so live with a general + // Exception for system stability's sake. + Slog.wtf(TAG, "Unexpected exception", e); } finally { if (mPersistInfo.countAllJobsLoaded < 0) { // Only set them once. mPersistInfo.countAllJobsLoaded = numJobs; @@ -817,6 +821,15 @@ private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser) } catch (NumberFormatException e) { Slog.d(TAG, "Error reading constraints, skipping."); return null; + } catch (XmlPullParserException e) { + Slog.d(TAG, "Error Parser Exception.", e); + return null; + } catch (IOException e) { + Slog.d(TAG, "Error I/O Exception.", e); + return null; + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Constraints contained invalid data", e); + return null; } parser.next(); // Consume @@ -912,8 +925,14 @@ private JobStatus restoreJobFromXml(boolean rtcIsGood, XmlPullParser parser) return null; } - PersistableBundle extras = PersistableBundle.restoreFromXml(parser); - jobBuilder.setExtras(extras); + final PersistableBundle extras; + try { + extras = PersistableBundle.restoreFromXml(parser); + jobBuilder.setExtras(extras); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Persisted extras contained invalid data", e); + return null; + } parser.nextTag(); // Consume final JobInfo builtJob; @@ -959,7 +978,8 @@ private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberF return new JobInfo.Builder(jobId, cname); } - private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) { + private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) + throws XmlPullParserException, IOException { String val; final String netCapabilities = parser.getAttributeValue(null, "net-capabilities"); 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 36ccaf9c6fb8..403e8b5547bd 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -233,6 +233,10 @@ static class Lock {} @GuardedBy("mActiveAdminApps") private final SparseArray> mActiveAdminApps = new SparseArray<>(); + /** List of admin protected packages. Can contain {@link android.os.UserHandle#USER_ALL}. */ + @GuardedBy("mAdminProtectedPackages") + private final SparseArray> mAdminProtectedPackages = new SparseArray<>(); + /** * Set of system apps that are headless (don't have any declared activities, enabled or * disabled). Presence in this map indicates that the app is a headless system app. @@ -1019,6 +1023,9 @@ public void onUserRemoved(int userId) { synchronized (mActiveAdminApps) { mActiveAdminApps.remove(userId); } + synchronized (mAdminProtectedPackages) { + mAdminProtectedPackages.remove(userId); + } } } @@ -1108,6 +1115,10 @@ private int getAppMinBucket(String packageName, int appId, int userId) { return STANDBY_BUCKET_EXEMPTED; } + if (isAdminProtectedPackages(packageName, userId)) { + return STANDBY_BUCKET_EXEMPTED; + } + if (isActiveNetworkScorer(packageName)) { return STANDBY_BUCKET_EXEMPTED; } @@ -1510,6 +1521,17 @@ boolean isActiveDeviceAdmin(String packageName, int userId) { } } + private boolean isAdminProtectedPackages(String packageName, int userId) { + synchronized (mAdminProtectedPackages) { + if (mAdminProtectedPackages.contains(UserHandle.USER_ALL) + && mAdminProtectedPackages.get(UserHandle.USER_ALL).contains(packageName)) { + return true; + } + return mAdminProtectedPackages.contains(userId) + && mAdminProtectedPackages.get(userId).contains(packageName); + } + } + @Override public void addActiveDeviceAdmin(String adminPkg, int userId) { synchronized (mActiveAdminApps) { @@ -1533,6 +1555,17 @@ public void setActiveAdminApps(Set adminPkgs, int userId) { } } + @Override + public void setAdminProtectedPackages(Set packageNames, int userId) { + synchronized (mAdminProtectedPackages) { + if (packageNames == null || packageNames.isEmpty()) { + mAdminProtectedPackages.remove(userId); + } else { + mAdminProtectedPackages.put(userId, packageNames); + } + } + } + @Override public void onAdminDataAvailable() { mAdminDataAvailableLatch.countDown(); @@ -1555,6 +1588,13 @@ Set getActiveAdminAppsForTest(int userId) { } } + @VisibleForTesting + Set getAdminProtectedPackagesForTest(int userId) { + synchronized (mAdminProtectedPackages) { + return mAdminProtectedPackages.get(userId); + } + } + /** * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, * returns {@code false}. diff --git a/api/current.txt b/api/current.txt index f94b45f19bd3..830fa2e7b1ac 100644 --- a/api/current.txt +++ b/api/current.txt @@ -438,6 +438,8 @@ package android { field public static final int collapseIcon = 16844031; // 0x10104ff field public static final int color = 16843173; // 0x10101a5 field public static final int colorAccent = 16843829; // 0x1010435 + field public static final int colorAccentBackground = 16844311; // 0x1010617 + field public static final int colorAccentOverlay = 16844312; // 0x1010618 field public static final int colorActivatedHighlight = 16843664; // 0x1010390 field public static final int colorBackground = 16842801; // 0x1010031 field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab @@ -1657,6 +1659,7 @@ package android { public static final class R.color { ctor public R.color(); + field public static final int accent_background_device_default = 17170461; // 0x106001d field public static final int background_dark = 17170446; // 0x106000e field public static final int background_light = 17170447; // 0x106000f field public static final int black = 17170444; // 0x106000c @@ -12541,6 +12544,20 @@ package android.content.pm { package android.content.res { + public class AccentUtils { + ctor public AccentUtils(); + method public int getBackgroundAccentColor(int); + method public int getDarkAccentColor(int); + method public int getLightAccentColor(int); + method public int getOverlayDarkAccentColor(int); + method public int getOverlayLightAccentColor(int); + method public boolean isResourceAccentBackground(@Nullable String); + method public boolean isResourceAccentOverlayDark(@Nullable String); + method public boolean isResourceAccentOverlayLight(@Nullable String); + method public boolean isResourceDarkAccent(@Nullable String); + method public boolean isResourceLightAccent(@Nullable String); + } + public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable { ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long); ctor public AssetFileDescriptor(android.os.ParcelFileDescriptor, long, long, android.os.Bundle); @@ -12722,6 +12739,23 @@ package android.content.res { field public int uiMode; } + public class MonetWannabe { + ctor public MonetWannabe(@NonNull android.content.Context); + method @ColorInt public static int adjustAlpha(@ColorInt int, float); + method public int getAccentColor(); + method public int getAccentColorBackground(); + method public int getAccentColorOverlayDark(); + method public int getAccentColorOverlayLight(); + method public static int getInactiveAccent(@NonNull android.content.Context); + method public static boolean isMonetEnabled(@NonNull android.content.Context); + method public static int manipulateColor(int, float); + method public static boolean shouldForceLoad(@NonNull android.content.Context); + method public static int updateMonet(@NonNull android.content.Context); + field public static final int DEFAULT_COLOR_GEN = 16; // 0x10 + field public static final float DEFAULT_DARK_ALTERATION = 0.8f; + field public static final float DEFAULT_LIGHT_ALTERATION = 0.7f; + } + public class ObbInfo implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -40776,6 +40810,7 @@ package android.provider { field public static final String BLUETOOTH_DISCOVERABILITY = "bluetooth_discoverability"; field public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT = "bluetooth_discoverability_timeout"; field @Deprecated public static final String BLUETOOTH_ON = "bluetooth_on"; + field public static final String BUTTON_BACKLIGHT_ONLY_WHEN_PRESSED = "button_backlight_only_when_pressed"; field public static final android.net.Uri CONTENT_URI; field @Deprecated public static final String DATA_ROAMING = "data_roaming"; field public static final String DATE_FORMAT = "date_format"; diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index ac00a042b79e..e52b9c177dc1 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -1982,6 +1982,10 @@ private void sendServiceInfo() { IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance().getConnection(mConnectionId); if (mInfo != null && connection != null) { + if (!mInfo.isWithinParcelableSize()) { + throw new IllegalStateException( + "Cannot update service info: size is larger than safe parcelable limits."); + } try { connection.setServiceInfo(mInfo); mInfo = null; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index a41fa6431d4d..f853dff01e8a 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -39,6 +39,7 @@ import android.graphics.drawable.Drawable; import android.hardware.fingerprint.FingerprintManager; import android.os.Build; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -1028,6 +1029,15 @@ public int describeContents() { return 0; } + /** @hide */ + public final boolean isWithinParcelableSize() { + final Parcel parcel = Parcel.obtain(); + writeToParcel(parcel, 0); + final boolean result = parcel.dataSize() <= IBinder.MAX_IPC_SIZE; + parcel.recycle(); + return result; + } + public void writeToParcel(Parcel parcel, int flagz) { parcel.writeInt(eventTypes); parcel.writeStringArray(packageNames); diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java index 8cdc6a71caf8..adfe171f1a8d 100644 --- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java +++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java @@ -407,7 +407,7 @@ public void run(final AccountManagerFuture accountManagerFuture) { mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage, mCallingUid); intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); - startActivityForResult(intent, REQUEST_ADD_ACCOUNT); + startActivityForResult(new Intent(intent), REQUEST_ADD_ACCOUNT); return; } } catch (OperationCanceledException e) { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 1059a6f2e868..811cd5b75275 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3933,6 +3933,9 @@ public void restartPackage(String packageName) { * processes to reclaim memory; the system will take care of restarting * these processes in the future as needed. * + *

Third party applications can only use this API to kill their own processes. + *

+ * * @param packageName The name of the package whose processes are to * be killed. */ diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 4aedfeefb72b..b8413c5aafcc 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -20,6 +20,8 @@ import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_RECEIVER_FOREGROUND; import static android.view.Display.INVALID_DISPLAY; import android.annotation.NonNull; @@ -61,7 +63,7 @@ * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle) * Context.startActivity(Intent, Bundle)} and related methods. */ -public class ActivityOptions { +public class ActivityOptions extends ComponentOptions { private static final String TAG = "ActivityOptions"; /** @@ -963,13 +965,12 @@ public boolean getLaunchTaskBehind() { } private ActivityOptions() { + super(); } /** @hide */ public ActivityOptions(Bundle opts) { - // If the remote side sent us bad parcelables, they won't get the - // results they want, which is their loss. - opts.setDefusable(true); + super(opts); mPackageName = opts.getString(KEY_PACKAGE_NAME); try { @@ -1373,7 +1374,9 @@ public void setPendingIntentLaunchFlags(@android.content.Intent.Flags int flags) * @hide */ public int getPendingIntentLaunchFlags() { - return mPendingIntentLaunchFlags; + // b/243794108: Ignore all flags except the new task flag, to be reconsidered in b/254490217 + return mPendingIntentLaunchFlags & + (FLAG_ACTIVITY_NEW_TASK | FLAG_RECEIVER_FOREGROUND); } /** @@ -1575,8 +1578,9 @@ public void update(ActivityOptions otherOptions) { * object; you must not modify it, but can supply it to the startActivity * methods that take an options Bundle. */ + @Override public Bundle toBundle() { - Bundle b = new Bundle(); + Bundle b = super.toBundle(); if (mPackageName != null) { b.putString(KEY_PACKAGE_NAME, mPackageName); } diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 7180c01143a5..9a92515ee794 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -45,6 +45,14 @@ public final class AutomaticZenRule implements Parcelable { private long creationTime; private ZenPolicy mZenPolicy; private boolean mModified = false; + private String mPkg; + + /** + * The maximum string length for any string contained in this automatic zen rule. This pertains + * both to fields in the rule itself (such as its name) and items with sub-fields. + * @hide + */ + public static final int MAX_STRING_LENGTH = 1000; /** * Creates an automatic zen rule. @@ -92,10 +100,10 @@ public AutomaticZenRule(String name, ComponentName owner, Uri conditionId, public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner, @Nullable ComponentName configurationActivity, @NonNull Uri conditionId, @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) { - this.name = name; - this.owner = owner; - this.configurationActivity = configurationActivity; - this.conditionId = conditionId; + this.name = getTrimmedString(name); + this.owner = getTrimmedComponentName(owner); + this.configurationActivity = getTrimmedComponentName(configurationActivity); + this.conditionId = getTrimmedUri(conditionId); this.interruptionFilter = interruptionFilter; this.enabled = enabled; this.mZenPolicy = policy; @@ -114,15 +122,16 @@ public AutomaticZenRule(String name, ComponentName owner, ComponentName configur public AutomaticZenRule(Parcel source) { enabled = source.readInt() == ENABLED; if (source.readInt() == ENABLED) { - name = source.readString(); + name = getTrimmedString(source.readString()); } interruptionFilter = source.readInt(); - conditionId = source.readParcelable(null); - owner = source.readParcelable(null); - configurationActivity = source.readParcelable(null); + conditionId = getTrimmedUri(source.readParcelable(null)); + owner = getTrimmedComponentName(source.readParcelable(null)); + configurationActivity = getTrimmedComponentName(source.readParcelable(null)); creationTime = source.readLong(); mZenPolicy = source.readParcelable(null); mModified = source.readInt() == ENABLED; + mPkg = source.readString(); } /** @@ -194,7 +203,7 @@ public long getCreationTime() { * Sets the representation of the state that causes this rule to become active. */ public void setConditionId(Uri conditionId) { - this.conditionId = conditionId; + this.conditionId = getTrimmedUri(conditionId); } /** @@ -209,7 +218,7 @@ public void setInterruptionFilter(@InterruptionFilter int interruptionFilter) { * Sets the name of this rule. */ public void setName(String name) { - this.name = name; + this.name = getTrimmedString(name); } /** @@ -241,7 +250,21 @@ public void setZenPolicy(ZenPolicy zenPolicy) { * that are not backed by {@link android.service.notification.ConditionProviderService}. */ public void setConfigurationActivity(@Nullable ComponentName componentName) { - this.configurationActivity = componentName; + this.configurationActivity = getTrimmedComponentName(componentName); + } + + /** + * @hide + */ + public void setPackageName(String pkgName) { + mPkg = pkgName; + } + + /** + * @hide + */ + public String getPackageName() { + return mPkg; } @Override @@ -265,6 +288,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(creationTime); dest.writeParcelable(mZenPolicy, 0); dest.writeInt(mModified ? ENABLED : DISABLED); + dest.writeString(mPkg); } @Override @@ -273,6 +297,7 @@ public String toString() { .append("enabled=").append(enabled) .append(",name=").append(name) .append(",interruptionFilter=").append(interruptionFilter) + .append(",pkg=").append(mPkg) .append(",conditionId=").append(conditionId) .append(",owner=").append(owner) .append(",configActivity=").append(configurationActivity) @@ -294,13 +319,14 @@ public boolean equals(Object o) { && Objects.equals(other.owner, owner) && Objects.equals(other.mZenPolicy, mZenPolicy) && Objects.equals(other.configurationActivity, configurationActivity) + && Objects.equals(other.mPkg, mPkg) && other.creationTime == creationTime; } @Override public int hashCode() { return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, - configurationActivity, mZenPolicy, mModified, creationTime); + configurationActivity, mZenPolicy, mModified, creationTime, mPkg); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR @@ -314,4 +340,35 @@ public AutomaticZenRule[] newArray(int size) { return new AutomaticZenRule[size]; } }; + + /** + * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH, + * return a trimmed version that truncates each of the package and class name at the max length. + */ + private static ComponentName getTrimmedComponentName(ComponentName cn) { + if (cn == null) return null; + return new ComponentName(getTrimmedString(cn.getPackageName()), + getTrimmedString(cn.getClassName())); + } + + /** + * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH. + */ + private static String getTrimmedString(String input) { + if (input != null && input.length() > MAX_STRING_LENGTH) { + return input.substring(0, MAX_STRING_LENGTH); + } + return input; + } + + /** + * Returns a truncated copy of the Uri by trimming the string representation to the maximum + * string length. + */ + private static Uri getTrimmedUri(Uri input) { + if (input != null && input.toString().length() > MAX_STRING_LENGTH) { + return Uri.parse(getTrimmedString(input.toString())); + } + return input; + } } diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index 161e2ad06ec0..8947fb44b07b 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -28,7 +28,7 @@ * {@hide} */ @SystemApi -public class BroadcastOptions { +public class BroadcastOptions extends ComponentOptions { private long mTemporaryAppWhitelistDuration; private int mMinManifestReceiverApiLevel = 0; private int mMaxManifestReceiverApiLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; @@ -72,10 +72,12 @@ public static BroadcastOptions makeBasic() { } private BroadcastOptions() { + super(); } /** @hide */ public BroadcastOptions(Bundle opts) { + super(opts); mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION); mMinManifestReceiverApiLevel = opts.getInt(KEY_MIN_MANIFEST_RECEIVER_API_LEVEL, 0); mMaxManifestReceiverApiLevel = opts.getInt(KEY_MAX_MANIFEST_RECEIVER_API_LEVEL, @@ -173,6 +175,24 @@ public boolean allowsBackgroundActivityStarts() { return mAllowBackgroundActivityStarts; } + /** + * Set PendingIntent activity is allowed to be started in the background if the caller + * can start background activities. + * @hide + */ + public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { + super.setPendingIntentBackgroundActivityLaunchAllowed(allowed); + } + + /** + * Get PendingIntent activity is allowed to be started in the background if the caller + * can start background activities. + * @hide + */ + public boolean isPendingIntentBackgroundActivityLaunchAllowed() { + return super.isPendingIntentBackgroundActivityLaunchAllowed(); + } + /** * Returns the created options as a Bundle, which can be passed to * {@link android.content.Context#sendBroadcast(android.content.Intent) @@ -181,8 +201,9 @@ public boolean allowsBackgroundActivityStarts() { * object; you must not modify it, but can supply it to the sendBroadcast * methods that take an options Bundle. */ + @Override public Bundle toBundle() { - Bundle b = new Bundle(); + Bundle b = super.toBundle(); if (mTemporaryAppWhitelistDuration > 0) { b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration); } diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java new file mode 100644 index 000000000000..34ee9138a364 --- /dev/null +++ b/core/java/android/app/ComponentOptions.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2022 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 android.app; + +import android.os.Bundle; + +/** + * @hide + */ +public class ComponentOptions { + + /** + * Default value for KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED. + * @hide + **/ + public static final boolean PENDING_INTENT_BAL_ALLOWED_DEFAULT = true; + + /** + * PendingIntent caller allows activity start even if PendingIntent creator is in background. + * This only works if the PendingIntent caller is allowed to start background activities, + * for example if it's in the foreground, or has BAL permission. + * @hide + */ + public static final String KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED = + "android.pendingIntent.backgroundActivityAllowed"; + + private boolean mPendingIntentBalAllowed = PENDING_INTENT_BAL_ALLOWED_DEFAULT; + + ComponentOptions() { + } + + ComponentOptions(Bundle opts) { + // If the remote side sent us bad parcelables, they won't get the + // results they want, which is their loss. + opts.setDefusable(true); + setPendingIntentBackgroundActivityLaunchAllowed( + opts.getBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, + PENDING_INTENT_BAL_ALLOWED_DEFAULT)); + } + + /** + * Set PendingIntent activity is allowed to be started in the background if the caller + * can start background activities. + * + * @hide + */ + public void setPendingIntentBackgroundActivityLaunchAllowed(boolean allowed) { + mPendingIntentBalAllowed = allowed; + } + + /** + * Get PendingIntent activity is allowed to be started in the background if the caller + * can start background activities. + * + * @hide + */ + public boolean isPendingIntentBackgroundActivityLaunchAllowed() { + return mPendingIntentBalAllowed; + } + + /** + * @hide + */ + public Bundle toBundle() { + Bundle bundle = new Bundle(); + bundle.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, + mPendingIntentBalAllowed); + return bundle; + } +} diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index d4a8b4b8674b..159e85a970bc 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -201,7 +201,7 @@ interface INotificationManager void setNotificationPolicyAccessGrantedForUser(String pkg, int userId, boolean granted); AutomaticZenRule getAutomaticZenRule(String id); List getZenRules(); - String addAutomaticZenRule(in AutomaticZenRule automaticZenRule); + String addAutomaticZenRule(in AutomaticZenRule automaticZenRule, String pkg); boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule); boolean removeAutomaticZenRule(String id); boolean removeAutomaticZenRules(String packageName); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index b1aed460f9fb..b06c06b817c9 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2476,6 +2476,14 @@ public void cloneInto(Notification that, boolean heavy) { } } + private static void visitIconUri(@NonNull Consumer visitor, @Nullable Icon icon) { + if (icon == null) return; + final int iconType = icon.getType(); + if (iconType == TYPE_URI || iconType == TYPE_URI_ADAPTIVE_BITMAP) { + visitor.accept(icon.getUri()); + } + } + /** * Note all {@link Uri} that are referenced internally, with the expectation * that Uri permission grants will need to be issued to ensure the recipient @@ -2484,6 +2492,10 @@ public void cloneInto(Notification that, boolean heavy) { * @hide */ public void visitUris(@NonNull Consumer visitor) { + if (publicVersion != null) { + publicVersion.visitUris(visitor); + } + visitor.accept(sound); if (tickerView != null) tickerView.visitUris(visitor); @@ -2491,7 +2503,18 @@ public void visitUris(@NonNull Consumer visitor) { if (bigContentView != null) bigContentView.visitUris(visitor); if (headsUpContentView != null) headsUpContentView.visitUris(visitor); + visitIconUri(visitor, mSmallIcon); + visitIconUri(visitor, mLargeIcon); + + if (actions != null) { + for (Action action : actions) { + visitIconUri(visitor, action.getIcon()); + } + } + if (extras != null) { + visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG)); + visitor.accept(extras.getParcelable(EXTRA_AUDIO_CONTENTS_URI)); if (extras.containsKey(EXTRA_BACKGROUND_IMAGE_URI)) { visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI))); @@ -2538,14 +2561,12 @@ public void visitUris(@NonNull Consumer visitor) { } } } + + visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON)); } - if (mBubbleMetadata != null && mBubbleMetadata.getIcon() != null) { - final Icon icon = mBubbleMetadata.getIcon(); - final int iconType = icon.getType(); - if (iconType == TYPE_URI_ADAPTIVE_BITMAP || iconType == TYPE_URI) { - visitor.accept(icon.getUri()); - } + if (mBubbleMetadata != null) { + visitIconUri(visitor, mBubbleMetadata.getIcon()); } } diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 8f2d28d1bb18..394b07a98b94 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -78,8 +78,13 @@ public final class NotificationChannel implements Parcelable { /** * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this * limit. + * @hide */ - private static final int MAX_TEXT_LENGTH = 1000; + public static final int MAX_TEXT_LENGTH = 1000; + /** + * @hide + */ + public static final int MAX_VIBRATION_LENGTH = 1000; private static final String TAG_CHANNEL = "channel"; private static final String ATT_NAME = "name"; @@ -242,17 +247,17 @@ public NotificationChannel(String id, CharSequence name, @Importance int importa */ protected NotificationChannel(Parcel in) { if (in.readByte() != 0) { - mId = in.readString(); + mId = getTrimmedString(in.readString()); } else { mId = null; } if (in.readByte() != 0) { - mName = in.readString(); + mName = getTrimmedString(in.readString()); } else { mName = null; } if (in.readByte() != 0) { - mDesc = in.readString(); + mDesc = getTrimmedString(in.readString()); } else { mDesc = null; } @@ -261,18 +266,22 @@ protected NotificationChannel(Parcel in) { mLockscreenVisibility = in.readInt(); if (in.readByte() != 0) { mSound = Uri.CREATOR.createFromParcel(in); + mSound = Uri.parse(getTrimmedString(mSound.toString())); } else { mSound = null; } mLights = in.readByte() != 0; mVibration = in.createLongArray(); + if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) { + mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH); + } mUserLockedFields = in.readInt(); mFgServiceShown = in.readByte() != 0; mVibrationEnabled = in.readByte() != 0; mShowBadge = in.readByte() != 0; mDeleted = in.readByte() != 0; if (in.readByte() != 0) { - mGroup = in.readString(); + mGroup = getTrimmedString(in.readString()); } else { mGroup = null; } @@ -284,8 +293,8 @@ protected NotificationChannel(Parcel in) { mAllowBubbles = in.readInt(); mImportanceLockedByOEM = in.readBoolean(); mOriginalImportance = in.readInt(); - mParentId = in.readString(); - mConversationId = in.readString(); + mParentId = getTrimmedString(in.readString()); + mConversationId = getTrimmedString(in.readString()); mDemoted = in.readBoolean(); mImportantConvo = in.readBoolean(); } diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java index 403fb3e3727c..07802a220015 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -42,8 +42,9 @@ public final class NotificationChannelGroup implements Parcelable { /** * The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at * this limit. + * @hide */ - private static final int MAX_TEXT_LENGTH = 1000; + public static final int MAX_TEXT_LENGTH = 1000; private static final String TAG_GROUP = "channelGroup"; private static final String ATT_NAME = "name"; @@ -89,13 +90,17 @@ public NotificationChannelGroup(String id, CharSequence name) { */ protected NotificationChannelGroup(Parcel in) { if (in.readByte() != 0) { - mId = in.readString(); + mId = getTrimmedString(in.readString()); } else { mId = null; } - mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readByte() != 0) { - mDescription = in.readString(); + mName = getTrimmedString(in.readString()); + } else { + mName = ""; + } + if (in.readByte() != 0) { + mDescription = getTrimmedString(in.readString()); } else { mDescription = null; } @@ -119,7 +124,12 @@ public void writeToParcel(Parcel dest, int flags) { } else { dest.writeByte((byte) 0); } - TextUtils.writeToParcel(mName, dest, flags); + if (mName != null) { + dest.writeByte((byte) 1); + dest.writeString(mName.toString()); + } else { + dest.writeByte((byte) 0); + } if (mDescription != null) { dest.writeByte((byte) 1); dest.writeString(mDescription); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 2049e021e548..b9ab5cd8c2af 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -465,6 +465,12 @@ public class NotificationManager { */ public static final int BUBBLE_PREFERENCE_SELECTED = 2; + /** + * Maximum length of the component name of a registered NotificationListenerService. + * @hide + */ + public static int MAX_SERVICE_COMPONENT_NAME_LENGTH = 500; + @UnsupportedAppUsage private static INotificationManager sService; @@ -1072,10 +1078,12 @@ public Map getAutomaticZenRules() { List rules = service.getZenRules(); Map ruleMap = new HashMap<>(); for (ZenModeConfig.ZenRule rule : rules) { - ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component, + AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity, rule.conditionId, rule.zenPolicy, zenModeToInterruptionFilter(rule.zenMode), rule.enabled, - rule.creationTime)); + rule.creationTime); + azr.setPackageName(rule.pkg); + ruleMap.put(rule.id, azr); } return ruleMap; } catch (RemoteException e) { @@ -1116,7 +1124,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) { public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { INotificationManager service = getService(); try { - return service.addAutomaticZenRule(automaticZenRule); + return service.addAutomaticZenRule(automaticZenRule, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9f6ac309e44d..5958a7934e52 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.Manifest.permission; +import android.accounts.Account; import android.annotation.CallbackExecutor; import android.annotation.ColorInt; import android.annotation.IntDef; @@ -152,6 +153,27 @@ public DevicePolicyManager(Context context, IDevicePolicyManager service) { this(context, service, false); } + /** + * Called when a managed profile has been provisioned. + * + * @throws SecurityException if the caller does not hold + * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + public void finalizeWorkProfileProvisioning( + @NonNull UserHandle managedProfileUser, @Nullable Account migratedAccount) { + Objects.requireNonNull(managedProfileUser, "managedProfileUser can't be null"); + if (mService == null) { + throw new IllegalStateException("Could not find DevicePolicyManagerService"); + } + try { + mService.finalizeWorkProfileProvisioning(managedProfileUser, migratedAccount); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ @VisibleForTesting protected DevicePolicyManager(Context context, IDevicePolicyManager service, @@ -9639,6 +9661,15 @@ public int getPermissionPolicy(ComponentName admin) { * {@link android.os.Build.VERSION_CODES#M} the app-op matching the permission is set to * {@link android.app.AppOpsManager#MODE_IGNORED}, but the permission stays granted. * + * Control over the following permissions are restricted for managed profile owners: + *
    + *
  • Manifest.permission.READ_SMS
  • + *
+ *

+ * A managed profile owner may not grant these permissions (i.e. call this method with any of + * the permissions listed above and {@code grantState} of + * {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them. + * * @param admin Which profile or device owner this request is associated with. * @param packageName The application to grant or revoke a permission to. * @param permission The permission to grant or revoke. @@ -9876,7 +9907,8 @@ public CharSequence getShortSupportMessage(@NonNull ComponentName admin) { /** * Called by a device admin to set the long support message. This will be displayed to the user - * in the device administators settings screen. + * in the device administrators settings screen. If the message is longer than 20000 characters + * it may be truncated. *

* If the long support message needs to be localized, it is the responsibility of the * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast @@ -11965,7 +11997,8 @@ public boolean startViewCalendarEventInManagedProfile(long eventId, long start, /** * Called by Device owner to disable user control over apps. User will not be able to clear - * app data or force-stop packages. + * app data or force-stop packages. Packages with user control disabled are exempted from + * App Standby Buckets. * * @param admin which {@link DeviceAdminReceiver} this request is associated with * @param packages The package names for the apps. diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index d24694faff93..60cb563cca3d 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -16,6 +16,7 @@ package android.app.admin; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; @@ -76,6 +77,13 @@ public interface OnCrossProfileWidgetProvidersChangeListener { public abstract void addOnCrossProfileWidgetProvidersChangeListener( OnCrossProfileWidgetProvidersChangeListener listener); + /** + * @param userHandle the handle of the user whose profile owner is being fetched. + * @return the configured supervision app if it exists and is the device owner or policy owner. + */ + public abstract @Nullable ComponentName getProfileOwnerOrDeviceOwnerSupervisionComponent( + @NonNull UserHandle userHandle); + /** * Checks if an app with given uid is an active device admin of its user and has the policy * specified. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 9c6a274ccf8c..7bc83e95d5af 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -17,6 +17,7 @@ package android.app.admin; +import android.accounts.Account; import android.app.admin.NetworkEvent; import android.app.IApplicationThread; import android.app.IServiceConnection; @@ -91,6 +92,8 @@ interface IDevicePolicyManager { int getCurrentFailedPasswordAttempts(int userHandle, boolean parent); int getProfileWithMinimumFailedPasswordsForWipe(int userHandle, boolean parent); + void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount); + void setMaximumFailedPasswordsForWipe(in ComponentName admin, int num, boolean parent); int getMaximumFailedPasswordsForWipe(in ComponentName admin, int userHandle, boolean parent); diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index 3fef92b203b6..e2351ee89c42 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -28,6 +28,7 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; @@ -250,19 +251,26 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto super.onLayout(changed, left, top, right, bottom); } catch (final RuntimeException e) { Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e); - removeViewInLayout(mView); - View child = getErrorView(); - prepareView(child); - addViewInLayout(child, 0, child.getLayoutParams()); - measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); - child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight, - child.getMeasuredHeight() + mPaddingTop + mPaddingBottom); - mView = child; - mViewMode = VIEW_MODE_ERROR; + handleViewError(); } } + /** + * Remove bad view and replace with error message view + */ + private void handleViewError() { + removeViewInLayout(mView); + View child = getErrorView(); + prepareView(child); + addViewInLayout(child, 0, child.getLayoutParams()); + measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight, + child.getMeasuredHeight() + mPaddingTop + mPaddingBottom); + mView = child; + mViewMode = VIEW_MODE_ERROR; + } + /** * Provide guidance about the size of this widget to the AppWidgetManager. The widths and * heights should correspond to the full area the AppWidgetHostView is given. Padding added by @@ -725,4 +733,15 @@ private OnClickHandler getHandler(OnClickHandler handler) { } }; } + + @Override + protected void dispatchDraw(Canvas canvas) { + try { + super.dispatchDraw(canvas); + } catch (Exception e) { + // Catch draw exceptions that may be caused by RemoteViews + Log.e(TAG, "Drawing view failed: " + e); + post(this::handleViewError); + } + } } diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 009ec522e436..287331aa6d6e 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -1109,7 +1109,9 @@ public void setBindAppWidgetPermission(String packageName, int userId, boolean p * @param intent The intent of the service which will be providing the data to the * RemoteViewsAdapter. * @param connection The callback interface to be notified when a connection is made or lost. - * @param flags Flags used for binding to the service + * @param flags Flags used for binding to the service. Currently only + * {@link Context#BIND_AUTO_CREATE} and + * {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported. * * @see Context#getServiceDispatcher(ServiceConnection, Handler, int) * @hide diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 4c595a9cb140..b1c7d6eadbba 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1230,7 +1230,10 @@ public String getAlias() { if (alias == null) { return getName(); } - return alias; + return alias + .replace('\t', ' ') + .replace('\n', ' ') + .replace('\r', ' '); } catch (RemoteException e) { Log.e(TAG, "", e); } diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index a086a308d0d9..da4ecdd8c1f2 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -21,6 +21,7 @@ import android.accounts.Account; import android.annotation.MainThread; import android.annotation.NonNull; +import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -171,8 +172,20 @@ private Account toSyncKey(Account account) { } private class ISyncAdapterImpl extends ISyncAdapter.Stub { + private boolean isCallerSystem() { + final long callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID) { + android.util.EventLog.writeEvent(0x534e4554, "203229608", -1, ""); + return false; + } + return true; + } + @Override public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) { + if (!isCallerSystem()) { + return; + } Handler.getMain().sendMessage(obtainMessage( AbstractThreadedSyncAdapter::handleOnUnsyncableAccount, AbstractThreadedSyncAdapter.this, cb)); @@ -181,12 +194,16 @@ public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) { @Override public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) { + if (!isCallerSystem()) { + return; + } if (ENABLE_LOG) { if (extras != null) { extras.size(); // Unparcel so its toString() will show the contents. } Log.d(TAG, "startSync() start " + authority + " " + account + " " + extras); } + try { final SyncContext syncContextClient = new SyncContext(syncContext); @@ -242,6 +259,9 @@ public void startSync(ISyncContext syncContext, String authority, Account accoun @Override public void cancelSync(ISyncContext syncContext) { + if (!isCallerSystem()) { + return; + } try { // synchronize to make sure that mSyncThreads doesn't change between when we // check it and when we use it diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index fa14cf5f9a30..0bc82902054c 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -10774,7 +10774,7 @@ private void toUriFragment(StringBuilder uri, String scheme, String defAction, private void toUriInner(StringBuilder uri, String scheme, String defAction, String defPackage, int flags) { if (scheme != null) { - uri.append("scheme=").append(scheme).append(';'); + uri.append("scheme=").append(Uri.encode(scheme)).append(';'); } if (mAction != null && !mAction.equals(defAction)) { uri.append("action=").append(Uri.encode(mAction)).append(';'); diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index f40dc298d560..b34b72254743 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -16,7 +16,9 @@ package android.content; +import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.ActivityOptions; import android.compat.annotation.UnsupportedAppUsage; import android.os.Bundle; import android.os.Handler; @@ -154,7 +156,7 @@ public void run() { */ public void sendIntent(Context context, int code, Intent intent, OnFinished onFinished, Handler handler) throws SendIntentException { - sendIntent(context, code, intent, onFinished, handler, null); + sendIntent(context, code, intent, onFinished, handler, null, null /* options */); } /** @@ -186,6 +188,42 @@ public void sendIntent(Context context, int code, Intent intent, public void sendIntent(Context context, int code, Intent intent, OnFinished onFinished, Handler handler, String requiredPermission) throws SendIntentException { + sendIntent(context, code, intent, onFinished, handler, requiredPermission, + null /* options */); + } + + /** + * Perform the operation associated with this IntentSender, allowing the + * caller to specify information about the Intent to use and be notified + * when the send has completed. + * + * @param context The Context of the caller. This may be null if + * intent is also null. + * @param code Result code to supply back to the IntentSender's target. + * @param intent Additional Intent data. See {@link Intent#fillIn + * Intent.fillIn()} for information on how this is applied to the + * original Intent. Use null to not modify the original Intent. + * @param onFinished The object to call back on when the send has + * completed, or null for no callback. + * @param handler Handler identifying the thread on which the callback + * should happen. If null, the callback will happen from the thread + * pool of the process. + * @param requiredPermission Name of permission that a recipient of the PendingIntent + * is required to hold. This is only valid for broadcast intents, and + * corresponds to the permission argument in + * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. + * If null, no permission is required. + * @param options Additional options the caller would like to provide to modify the sending + * behavior. May be built from an {@link ActivityOptions} to apply to an activity start. + * + * @throws SendIntentException Throws CanceledIntentException if the IntentSender + * is no longer allowing more intents to be sent through it. + * @hide + */ + public void sendIntent(Context context, int code, Intent intent, + OnFinished onFinished, Handler handler, String requiredPermission, + @Nullable Bundle options) + throws SendIntentException { try { String resolvedType = intent != null ? intent.resolveTypeIfNeeded(context.getContentResolver()) @@ -195,7 +233,7 @@ public void sendIntent(Context context, int code, Intent intent, onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, - requiredPermission, null); + requiredPermission, options); if (res < 0) { throw new SendIntentException(); } diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl index 63e7f2b33f26..3d7e3befd9f1 100644 --- a/core/java/android/content/om/IOverlayManager.aidl +++ b/core/java/android/content/om/IOverlayManager.aidl @@ -163,6 +163,4 @@ interface IOverlayManager { * @param packageName The name of the overlay package whose idmap should be deleted. */ void invalidateCachesForOverlay(in String packageName, in int userIs); - void reloadAssets(in String packageName, in int userId); - void reloadAndroidAssets(in int userId); } diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl index fc20263fe00a..de76a68e1d92 100644 --- a/core/java/android/content/pm/IPackageInstallerSession.aidl +++ b/core/java/android/content/pm/IPackageInstallerSession.aidl @@ -51,4 +51,5 @@ interface IPackageInstallerSession { int getParentSessionId(); boolean isStaged(); + int getInstallFlags(); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 191c4655c708..d56f19909dc7 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1358,6 +1358,18 @@ public boolean isStaged() { } } + /** + * @return Session's {@link SessionParams#installFlags}. + * @hide + */ + public int getInstallFlags() { + try { + return mSession.getInstallFlags(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * @return the session ID of the multi-package session that this belongs to or * {@link SessionInfo#INVALID_ID} if it does not belong to a multi-package session. diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index 1b3c46f90851..bf1219ccd872 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -261,6 +261,12 @@ public final class ShortcutInfo implements Parcelable { */ public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103; + /** + * The maximum length of Shortcut ID. IDs will be truncated at this limit. + * @hide + */ + public static final int MAX_ID_LENGTH = 1000; + /** @hide */ @IntDef(prefix = { "DISABLED_REASON_" }, value = { DISABLED_REASON_NOT_DISABLED, @@ -436,8 +442,7 @@ public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReas private ShortcutInfo(Builder b) { mUserId = b.mContext.getUserId(); - - mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"); + mId = getSafeId(Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided")); // Note we can't do other null checks here because SM.updateShortcuts() takes partial // information. @@ -539,6 +544,14 @@ private static Person[] clonePersons(Person[] persons) { return ret; } + @NonNull + private static String getSafeId(@NonNull String id) { + if (id.length() > MAX_ID_LENGTH) { + return id.substring(0, MAX_ID_LENGTH); + } + return id; + } + /** * Throws if any of the mandatory fields is not set. * @@ -2090,7 +2103,8 @@ private ShortcutInfo(Parcel source) { final ClassLoader cl = getClass().getClassLoader(); mUserId = source.readInt(); - mId = source.readString8(); + mId = getSafeId(Preconditions.checkStringNotEmpty(source.readString8(), + "Shortcut ID must be provided")); mPackageName = source.readString8(); mActivity = source.readParcelable(cl); mFlags = source.readInt(); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index 4009289e8838..6ae560d56a34 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -1007,7 +1007,7 @@ public void writeToParcel(Parcel dest, int flags) { sForInternedStringList.parcel(this.requestedPermissions, dest, flags); sForInternedStringList.parcel(this.implicitPermissions, dest, flags); sForStringSet.parcel(this.upgradeKeySets, dest, flags); - dest.writeMap(this.keySetMapping); + ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping); sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags); dest.writeTypedList(this.activities); dest.writeTypedList(this.receivers); @@ -1026,7 +1026,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeBoolean(this.use32BitAbi); dest.writeBoolean(this.visibleToInstantApps); dest.writeBoolean(this.forceQueryable); - dest.writeParcelableList(this.queriesIntents, flags); + dest.writeTypedList(this.queriesIntents, flags); sForInternedStringList.parcel(this.queriesPackages, dest, flags); sForInternedStringSet.parcel(this.queriesProviders, dest, flags); dest.writeString(this.appComponentFactory); @@ -1169,7 +1169,7 @@ public ParsingPackageImpl(Parcel in) { this.requestedPermissions = sForInternedStringList.unparcel(in); this.implicitPermissions = sForInternedStringList.unparcel(in); this.upgradeKeySets = sForStringSet.unparcel(in); - this.keySetMapping = in.readHashMap(boot); + this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in); this.protectedBroadcasts = sForInternedStringList.unparcel(in); this.activities = in.createTypedArrayList(ParsedActivity.CREATOR); @@ -1584,6 +1584,9 @@ private void addMimeGroupsFromComponent(ParsedComponent component) { for (int i = component.getIntents().size() - 1; i >= 0; i--) { IntentFilter filter = component.getIntents().get(i); for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) { + if (mimeGroups != null && mimeGroups.size() > 500) { + throw new IllegalStateException("Max limit on number of MIME Groups reached"); + } mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex)); } } diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index 27016e8e3f0f..cebee700ddfe 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; @@ -84,6 +85,7 @@ import android.os.Build; import android.os.Bundle; import android.os.FileUtils; +import android.os.Parcel; import android.os.RemoteException; import android.os.Trace; import android.os.ext.SdkExtensions; @@ -777,6 +779,13 @@ private ParseResult parseBaseApkTags(ParseInput input, ParsingPa ); } + if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) { + return input.error( + INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Found duplicate permission with a different attribute value." + ); + } + convertNewPermissions(pkg); convertSplitPermissions(pkg); @@ -2832,6 +2841,68 @@ private static String nonResString(@StyleableRes int index, TypedArray sa) { return sa.getNonResourceString(index); } + /** + * Writes the keyset mapping to the provided package. {@code null} mappings are permitted. + */ + public static void writeKeySetMapping(@NonNull Parcel dest, + @NonNull Map> keySetMapping) { + if (keySetMapping == null) { + dest.writeInt(-1); + return; + } + + final int N = keySetMapping.size(); + dest.writeInt(N); + + for (String key : keySetMapping.keySet()) { + dest.writeString(key); + ArraySet keys = keySetMapping.get(key); + if (keys == null) { + dest.writeInt(-1); + continue; + } + + final int M = keys.size(); + dest.writeInt(M); + for (int j = 0; j < M; j++) { + dest.writeSerializable(keys.valueAt(j)); + } + } + } + + /** + * Reads a keyset mapping from the given parcel at the given data position. May return + * {@code null} if the serialized mapping was {@code null}. + */ + @NonNull + public static ArrayMap> readKeySetMapping(@NonNull Parcel in) { + final int N = in.readInt(); + if (N == -1) { + return null; + } + + ArrayMap> keySetMapping = new ArrayMap<>(); + for (int i = 0; i < N; ++i) { + String key = in.readString(); + final int M = in.readInt(); + if (M == -1) { + keySetMapping.put(key, null); + continue; + } + + ArraySet keys = new ArraySet<>(M); + for (int j = 0; j < M; ++j) { + PublicKey pk = (PublicKey) in.readSerializable(); + keys.add(pk); + } + + keySetMapping.put(key, keys); + } + + return keySetMapping; + } + + /** * Callback interface for retrieving information that may be needed while parsing * a package. diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java index 1884a1e27832..fa7cfceb1a4c 100644 --- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java @@ -22,6 +22,8 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.util.ArrayMap; +import android.util.EventLog; import android.util.Slog; import com.android.internal.R; @@ -32,6 +34,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.List; +import java.util.Objects; /** @hide */ public class ParsedPermissionUtils { @@ -207,4 +211,48 @@ public static ParseResult parsePermissionGroup(ParsingPac return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permissionGroup, input); } + + /** + * Determines if a duplicate permission is malformed .i.e. defines different protection level + * or group. + */ + private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) { + // Since a permission tree is also added as a permission with normal protection + // level, we need to skip if the parsedPermission is a permission tree. + if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) { + return false; + } + + if (p1.getProtectionLevel() != p2.getProtectionLevel()) { + return true; + } + if (!Objects.equals(p1.getGroup(), p2.getGroup())) { + return true; + } + + return false; + } + + /** + * @return {@code true} if the package declares malformed duplicate permissions. + */ + public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) { + final List permissions = pkg.getPermissions(); + final int size = permissions.size(); + if (size > 0) { + final ArrayMap checkDuplicatePerm = new ArrayMap<>(size); + for (int i = 0; i < size; i++) { + final ParsedPermission parsedPermission = permissions.get(i); + final String name = parsedPermission.getName(); + final ParsedPermission perm = checkDuplicatePerm.get(name); + if (isMalformedDuplicate(parsedPermission, perm)) { + // Fix for b/213323615 + EventLog.writeEvent(0x534e4554, "213323615"); + return true; + } + checkDuplicatePerm.put(name, parsedPermission); + } + } + return false; + } } diff --git a/core/java/android/content/res/AccentUtils.java b/core/java/android/content/res/AccentUtils.java index db98e48e649c..04d066ad7127 100644 --- a/core/java/android/content/res/AccentUtils.java +++ b/core/java/android/content/res/AccentUtils.java @@ -1,45 +1,275 @@ package android.content.res; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.graphics.Color; -import android.os.SystemProperties; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; +import android.content.Context; +import android.provider.Settings; +import android.app.ActivityThread; /** @hide */ public class AccentUtils { - private static final String TAG = "AccentUtils"; - private static ArrayList accentResources = new ArrayList<>( - Arrays.asList("accent_device_default", - "accent_device_default_light", - "accent_device_default_dark", - "gradient_start")); + private MonetWannabe monet; + private Context context; + + public AccentUtils() { + context = ActivityThread.currentApplication(); + monet = new MonetWannabe(context); + } + + private final String ACCENT_DARK_SETTING = "accent_dark"; + private final String ACCENT_LIGHT_SETTING = "accent_light"; + + public int applyOverride(@Nullable String resName, int defaultColor) { + int resource = defaultColor; + /* System Colors */ + if (isResourceDarkAccent(resName)) + resource = getDarkAccentColor(defaultColor); + else if (isResourceLightAccent(resName)) + resource = getLightAccentColor(defaultColor); + else if (isResourceAccentSecondary(resName)) + resource = getAccentColorSecondary(defaultColor); + else if (isResourceAccentTertiary(resName)) + resource = getAccentColorTertiary(defaultColor); + else if (isResourceBackgroundColor(resName)) + resource = getBackgroundColor(defaultColor); + else if (isResourceBackgroundSecondary(resName)) + resource = getBackgroundSecondaryColor(defaultColor); + /* Keyguard Colors */ + else if (isResourceAccentKeyguard(resName)) + resource = getKeyguardAccentColor(resName, defaultColor); + else if (isResourceKeyguardBackgroundColor(resName)) + resource = getKeyguardBackgroundColor(defaultColor); + else if (isResourceKeyguardBackgroundSecondary(resName)) + resource = getKeyguardBackgroundSecondaryColor(defaultColor); + /* Extra Colors */ + else if (isResourceAccentBackground(resName)) + resource = getQSBackgroundAccentColor(defaultColor); + else if (isResourceAccentOverlay(resName)) + resource = getOverlayAccentColor(defaultColor); + return resource; + } + + public boolean isResourceDarkAccent(@Nullable String resName) { + return resName != null && resName.contains("accent_device_default_dark"); + } + + public boolean isResourceLightAccent(@Nullable String resName) { + return resName != null && resName.contains("accent_device_default_light"); + } + + public boolean isResourceAccentSecondary(@Nullable String resName) { + return resName != null && resName.contains("monet_accent_secondary_device_default"); + } + + public boolean isResourceAccentTertiary(@Nullable String resName) { + return resName != null && resName.contains("monet_accent_tertiary_device_default"); + } + + public boolean isResourceAccentBackground(@Nullable String resName) { + return resName != null && resName.contains("accent_background_device_default"); + } + + public boolean isResourceAccentOverlay(@Nullable String resName) { + return resName != null && resName.contains("accent_overlay_device_default"); + } + + public boolean isResourceAccentKeyguard(@Nullable String resName) { + return resName != null && resName.contains("monet_clock_color_device_default"); + } + + public boolean isResourceBackgroundColor(@Nullable String resName) { + return resName != null && resName.contains("dialogBackgroundColor") || + resName.contains("notification_material_background_color") || + resName.contains("monet_background_device_default"); + } + + public boolean isResourceBackgroundSecondary(@Nullable String resName) { + return resName != null && resName.contains("dialogSubBackgroundColor") || + resName.contains("monet_contextual_color_device_default") || + resName.contains("monet_background_secondary_device_default"); + } + + public boolean isResourceKeyguardBackgroundColor(@Nullable String resName) { + return resName != null && resName.contains("monet_lockscreen_background_device_default"); + } + + public boolean isResourceKeyguardBackgroundSecondary(@Nullable String resName) { + return resName != null && resName.contains("monet_lockscreen_background_secondary_device_default"); + } + + public int getDarkAccentColor(int defaultColor) { + return getAccentColor(monet, defaultColor, ACCENT_DARK_SETTING); + } + + public int getLightAccentColor(int defaultColor) { + return getAccentColor(monet, defaultColor, ACCENT_LIGHT_SETTING); + } + + public int getAccentColorSecondary(int defaultColor) { + return getAccentColorSecondary(monet, defaultColor, ACCENT_LIGHT_SETTING); + } + + public int getAccentColorTertiary(int defaultColor) { + return getAccentColorTertiary(monet, defaultColor, ACCENT_LIGHT_SETTING); + } + + public int getKeyguardAccentColor(@Nullable String resName, int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getKeyguardAccentColor(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + if (isResourceDarkAccent(resName)) + return getDarkAccentColor(defaultColor); + else if (isResourceLightAccent(resName)) + return getLightAccentColor(defaultColor); + else + return defaultColor; + } + } catch (Exception e) { + return defaultColor; + } + } + + public int getKeyguardBackgroundColor(int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getKeyguardBackground(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } + + } catch (Exception e) { + return defaultColor; + } + } - private static final String ACCENT_COLOR_PROP = "persist.sys.theme.accentcolor"; + public int getKeyguardBackgroundSecondaryColor(int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getKeyguardBackgroundSecondary(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } + + } catch (Exception e) { + return defaultColor; + } + } + + public int getBackgroundColor(int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getAccentColorBackground(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } + + } catch (Exception e) { + return defaultColor; + } + } - static boolean isResourceAccent(String resName) { - for (String ar : accentResources) - if (resName.contains(ar)) - return true; - return false; + public int getBackgroundSecondaryColor(int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getAccentColorBackgroundSecondary(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } + + } catch (Exception e) { + return defaultColor; + } } - public static int getNewAccentColor(int defaultColor) { - return getAccentColor(defaultColor, ACCENT_COLOR_PROP); + public int getQSBackgroundAccentColor(int defaultColor) { + try { + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getAccentColorQSBackground(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } + + } catch (Exception e) { + return defaultColor; + } } - private static int getAccentColor(int defaultColor, String property) { + public int getOverlayAccentColor(int defaultColor) { try { - String colorValue = SystemProperties.get(property, "-1"); - return "-1".equals(colorValue) - ? defaultColor - : Color.parseColor("#" + colorValue); + if (MonetWannabe.isMonetEnabled(context)) { + int colorValue = monet.getAccentColorQSOverlay(); + return colorValue == -1 ? defaultColor : colorValue; + } else { + return defaultColor; + } } catch (Exception e) { - Log.e(TAG, "Failed to set accent: " + e.getMessage() + - "\nSetting default: " + defaultColor); return defaultColor; } } + + private int getAccentColor(@NonNull MonetWannabe monet, int defaultColor, String setting) { + if (!MonetWannabe.isMonetEnabled(context)) { + try { + String colorValue = Settings.Secure.getString(context.getContentResolver(), setting); + return (colorValue == null || "-1".equals(colorValue)) ? + defaultColor : Color.parseColor("#" + colorValue); + } catch (Exception e) { + return defaultColor; + } + } else { + try { + int colorValue = monet.getAccentColor(); + return colorValue == -1 ? defaultColor : colorValue; + } catch (Exception e) { + return defaultColor; + } + } + } + + private int getAccentColorSecondary(@NonNull MonetWannabe monet, int defaultColor, String setting) { + if (!MonetWannabe.isMonetEnabled(context)) { + try { + String colorValue = Settings.Secure.getString(context.getContentResolver(), setting); + return (colorValue == null || "-1".equals(colorValue)) ? + defaultColor : Color.parseColor("#" + colorValue); + } catch (Exception e) { + return defaultColor; + } + } else { + try { + int colorValue = monet.getAccentColoSecondary(); + return colorValue == -1 ? defaultColor : colorValue; + } catch (Exception e) { + return defaultColor; + } + } + } + + private int getAccentColorTertiary(@NonNull MonetWannabe monet, int defaultColor, String setting) { + if (!MonetWannabe.isMonetEnabled(context)) { + try { + String colorValue = Settings.Secure.getString(context.getContentResolver(), setting); + return (colorValue == null || "-1".equals(colorValue)) ? + defaultColor : Color.parseColor("#" + colorValue); + } catch (Exception e) { + return defaultColor; + } + } else { + try { + int colorValue = monet.getAccentColorTertiary(); + return colorValue == -1 ? defaultColor : colorValue; + } catch (Exception e) { + return defaultColor; + } + } + } } diff --git a/core/java/android/content/res/MonetWannabe.java b/core/java/android/content/res/MonetWannabe.java new file mode 100644 index 000000000000..f20e23ac92b6 --- /dev/null +++ b/core/java/android/content/res/MonetWannabe.java @@ -0,0 +1,233 @@ +package android.content.res; + +import android.annotation.ColorInt; +import android.annotation.NonNull; +import android.content.Context; +import android.graphics.Color; +import android.provider.Settings; + +import com.android.internal.graphics.ColorUtils; + +import java.util.HashMap; + +/** + * @hide + */ +public class MonetWannabe { + + private final Context context; + + /** + * Color Shades + */ + + // System + private int accentColor; + private int accentColorSecondary; + private int accentColorTertiary; + private int accentColorBackground; + private int accentColorBackgroundSecondary; + + // Keyguard + private int accentColorKeyguard; + private int accentColorKeyguardBackground; + private int accentColorKeyguardBackgroundSecondary; + + // Extra + private int accentColorQSBackground; + private int accentColorQSOverlay; + + + public static final float DEFAULT_LIGHT_ALTERATION = 0.7f; + public static final float DEFAULT_DARK_ALTERATION = 0.8f; + + boolean isDarkMode = Resources.getSystem().getConfiguration().isNightModeActive(); + + /** + * MonetWannabe 2.0 + */ + public MonetWannabe(@NonNull Context context) { + this.context = context; + if (isMonetEnabled(context)) generateColors(); + } + + private void generateColors() { + HashMap monetColors = updateMonet(); + + /* System */ + accentColor = isDarkMode ? monetColors.get("accentColor") : + monetColors.get("accentColorLight"); + accentColorSecondary = isDarkMode ? monetColors.get("accentColorSecondary") : + monetColors.get("accentColorSecondaryLight"); + accentColorTertiary = isDarkMode ? monetColors.get("accentColorTertiary") : + monetColors.get("accentColorTertiaryLight"); + accentColorBackground = isDarkMode ? monetColors.get("backgroundColor") : + monetColors.get("backgroundColorLight"); + accentColorBackgroundSecondary = isDarkMode ? monetColors.get("backgroundSecondaryColor") : + monetColors.get("backgroundSecondaryColorLight"); + + /* Extra */ + accentColorQSBackground = isDarkMode ? manipulateColor(accentColor, 0.6f) : manipulateColor(accentColor, 0.8f); + accentColorQSOverlay = isDarkMode ? getDarkCousinColor(accentColor) : getLightCousinColor(accentColor); + + /* Keyguard */ + accentColorKeyguard = isDarkMode ? monetColors.get("keyguardAccentColor") : + monetColors.get("keyguardAccentColorLight"); + accentColorKeyguardBackground = isDarkMode ? monetColors.get("keyguardBackgroundColor") : + monetColors.get("keyguardBackgroundColorLight"); + accentColorKeyguardBackgroundSecondary = isDarkMode ? monetColors.get("keyguardBackgroundSecondaryColor") : + monetColors.get("keyguardBackgroundSecondaryColorLight"); + } + + public int getAccentColor() { + return accentColor; + } + + public int getAccentColoSecondary() { + return accentColorSecondary; + } + + public int getAccentColorTertiary() { + return accentColorTertiary; + } + + public int getAccentColorQSBackground() { + return accentColorQSBackground; + } + + public int getAccentColorQSOverlay() { + return accentColorQSOverlay; + } + + public int getAccentColorBackground() { + return accentColorBackground; + } + + public int getAccentColorBackgroundSecondary() { + return accentColorBackgroundSecondary; + } + + public int getKeyguardAccentColor() { + return accentColorKeyguard; + } + + public int getKeyguardBackground() { + return accentColorKeyguardBackground; + } + + public int getKeyguardBackgroundSecondary() { + return accentColorKeyguardBackgroundSecondary; + } + + private HashMap updateMonet() { + HashMap colorHashMap = new HashMap<>(); + + colorHashMap.put("accentColor", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT)); + colorHashMap.put("accentColorLight", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT_LIGHT)); + + /* Start of nullable accents */ + colorHashMap.put("accentColorSecondary", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT_SECONDARY)); + colorHashMap.put("accentColorSecondaryLight", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT_SECONDARY_LIGHT)); + + colorHashMap.put("accentColorTertiary", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT_TERTIARY)); + colorHashMap.put("accentColorTertiaryLight", + getMonetColorSetting(Settings.Secure.MONET_BASE_ACCENT_TERTIARY_LIGHT)); + + /* + * Handle nullability + * If one of the nullable accents are null, replace it with the main accent + * Their Setting will be null every wallpaper change and used on demand + */ + if (colorHashMap.get("accentColorSecondary") == -1 || colorHashMap.get("accentColorSecondaryLight") == -1) { + colorHashMap.put("accentColorSecondary", colorHashMap.get("accentColor")); + colorHashMap.put("accentColorSecondaryLight", colorHashMap.get("accentColorLight")); + } + if (colorHashMap.get("accentColorTertiary") == -1 || colorHashMap.get("accentColorTertiaryLight") == -1) { + colorHashMap.put("accentColorTertiary", colorHashMap.get("accentColor")); + colorHashMap.put("accentColorTertiaryLight", colorHashMap.get("accentColorLight")); + } + /* End of nullable accents */ + + colorHashMap.put("backgroundColor", + getMonetColorSetting(Settings.Secure.MONET_BACKGROUND)); + colorHashMap.put("backgroundColorLight", + getMonetColorSetting(Settings.Secure.MONET_BACKGROUND_LIGHT)); + + colorHashMap.put("backgroundSecondaryColor", + getMonetColorSetting(Settings.Secure.MONET_BACKGROUND_SECONDARY)); + colorHashMap.put("backgroundSecondaryColorLight", + getMonetColorSetting(Settings.Secure.MONET_BACKGROUND_SECONDARY_LIGHT)); + + colorHashMap.put("keyguardAccentColor", + getMonetColorSetting(Settings.Secure.MONET_BASE_KEYGUARD_ACCENT)); + colorHashMap.put("keyguardAccentColorLight", + getMonetColorSetting(Settings.Secure.MONET_BASE_KEYGUARD_ACCENT_LIGHT)); + + colorHashMap.put("keyguardBackgroundColor", + getMonetColorSetting(Settings.Secure.MONET_KEYGUARD_BACKGROUND)); + colorHashMap.put("keyguardBackgroundColorLight", + getMonetColorSetting(Settings.Secure.MONET_KEYGUARD_BACKGROUND_LIGHT)); + + colorHashMap.put("keyguardBackgroundSecondaryColor", + getMonetColorSetting(Settings.Secure.MONET_KEYGUARD_BACKGROUND_SECONDARY)); + colorHashMap.put("keyguardBackgroundSecondaryColorLight", + getMonetColorSetting(Settings.Secure.MONET_KEYGUARD_BACKGROUND_SECONDARY_LIGHT)); + return colorHashMap; + } + + private int getMonetColorSetting(String settingsName) { + String color = Settings.Secure.getString(context.getContentResolver(), settingsName); + return color == null || color.equals("-1") ? -1 : Integer.parseInt(color); + } + + private int getLightCousinColor(int darkColor) { + return adjustAlpha(ColorUtils.blendARGB(darkColor, Color.WHITE, DEFAULT_LIGHT_ALTERATION), 1f); + } + + private int getDarkCousinColor(int lightColor) { + return adjustAlpha(ColorUtils.blendARGB(lightColor, Color.BLACK, DEFAULT_DARK_ALTERATION), 1f); + } + + /** + * Manipulate color + * + * @param color original color + * @param factor under 1.0f to darken, over 1.0f to lighten + * @return altered color + */ + public static int manipulateColor(int color, float factor) { + int a = Color.alpha(color); + int r = Math.round(Color.red(color) * factor); + int g = Math.round(Color.green(color) * factor); + int b = Math.round(Color.blue(color) * factor); + return Color.argb(a, Math.min(r, 255), Math.min(g, 255), Math.min(b, 255)); + } + + @ColorInt + public static int adjustAlpha(@ColorInt int color, float factor) { + return ColorUtils.setAlphaComponent(color, Math.round((float) Color.alpha(color) * factor)); + } + + public static int getInactiveAccent(@NonNull Context context) { + boolean isDarkMode = Resources.getSystem().getConfiguration().isNightModeActive(); + return adjustAlpha(Resources.getSystem().getColor(android.R.color.accent_background_device_default, context.getTheme()), isDarkMode ? 0.6f : 0.3f); + } + + public static boolean isMonetEnabled(@NonNull Context context) { + return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.MONET_ENGINE, 1) == 1; + } + + public static boolean shouldForceLoad(@NonNull Context context) { + String accent = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.MONET_BASE_ACCENT); + boolean mainAccentFine = accent == null || accent.equals("-1"); + String accentKeyguard = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.MONET_BASE_KEYGUARD_ACCENT); + boolean keyguardAccentFine = accentKeyguard == null || accentKeyguard.equals("-1"); + return !(mainAccentFine && keyguardAccentFine); + } + +} diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 32c5b99e3377..854fcc37ba26 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1061,9 +1061,9 @@ public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundExce && value.type <= TypedValue.TYPE_LAST_INT) { if (id != 0) { try { + AccentUtils utils = new AccentUtils(); String resName = getResourceName(id); - if (AccentUtils.isResourceAccent(resName)) - value.data = AccentUtils.getNewAccentColor(value.data); + value.data = utils.applyOverride(resName, value.data); } catch (NotFoundException ignored) { } catch (Exception ex) { Log.e(TAG, ex.getMessage()); diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 8cf00ec8d2d4..04a516ef2c70 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -671,8 +671,8 @@ Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int if (id != 0) { try { String resName = getResourceName(id); - if (AccentUtils.isResourceAccent(resName)) - value.data = AccentUtils.getNewAccentColor(value.data); + AccentUtils utils = new AccentUtils(); + value.data = utils.applyOverride(resName, value.data); } catch (NotFoundException ignored) { } catch (Exception ex) { Log.e(TAG, ex.getMessage()); @@ -1069,8 +1069,8 @@ ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int if (id != 0) { try { String resName = getResourceName(id); - if (AccentUtils.isResourceAccent(resName)) - value.data = AccentUtils.getNewAccentColor(value.data); + AccentUtils utils = new AccentUtils(); + value.data = utils.applyOverride(resName, value.data); } catch (NotFoundException ignored) { } catch (Exception ex) { Log.e(TAG, ex.getMessage()); @@ -1120,8 +1120,8 @@ ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, if (id != 0) { try { String resName = getResourceName(id); - if (AccentUtils.isResourceAccent(resName)) - value.data = AccentUtils.getNewAccentColor(value.data); + AccentUtils utils = new AccentUtils(); + value.data = utils.applyOverride(resName, value.data); } catch (NotFoundException ignored) { } catch (Exception ex) { Log.e(TAG, ex.getMessage()); diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index f26f1baceca8..76497e226c20 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -516,11 +516,12 @@ public int getColor(@StyleableRes int index, @ColorInt int defValue) { try { int resId = data[index + 3]; + if (resId > 0) { String resName = this.mAssets.getResourceName(resId); int newColor = defValue; - if (AccentUtils.isResourceAccent(resName)) - newColor = AccentUtils.getNewAccentColor(defValue); + AccentUtils utils = new AccentUtils(); + newColor = utils.applyOverride(resName, defValue); if (newColor != defValue) return newColor; } diff --git a/core/java/android/debug/AdbManager.java b/core/java/android/debug/AdbManager.java index 7714dd80f910..243f80187185 100644 --- a/core/java/android/debug/AdbManager.java +++ b/core/java/android/debug/AdbManager.java @@ -38,6 +38,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_STATE_CHANGED_ACTION = "com.android.server.adb.WIRELESS_DEBUG_STATUS"; @@ -46,6 +47,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_PAIRED_DEVICES_ACTION = "com.android.server.adb.WIRELESS_DEBUG_PAIRED_DEVICES"; @@ -59,6 +61,7 @@ public class AdbManager { * * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_DEBUGGING) public static final String WIRELESS_DEBUG_PAIRING_RESULT_ACTION = "com.android.server.adb.WIRELESS_DEBUG_PAIRING_RESULT"; diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index 226b8e549a9e..c062f8c13d75 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -631,13 +631,7 @@ public int getSurfaceGroupId() { new Parcelable.Creator() { @Override public OutputConfiguration createFromParcel(Parcel source) { - try { - OutputConfiguration outputConfiguration = new OutputConfiguration(source); - return outputConfiguration; - } catch (Exception e) { - Log.e(TAG, "Exception creating OutputConfiguration from parcel", e); - return null; - } + return new OutputConfiguration(source); } @Override diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java index 47a897cb2c55..010b083633f5 100644 --- a/core/java/android/hardware/camera2/params/SessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java @@ -143,13 +143,7 @@ private SessionConfiguration(@NonNull Parcel source) { new Parcelable.Creator () { @Override public SessionConfiguration createFromParcel(Parcel source) { - try { - SessionConfiguration sessionConfiguration = new SessionConfiguration(source); - return sessionConfiguration; - } catch (Exception e) { - Log.e(TAG, "Exception creating SessionConfiguration from parcel", e); - return null; - } + return new SessionConfiguration(source); } @Override diff --git a/core/java/android/hardware/camera2/params/VendorTagDescriptor.java b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java index 4845ec3e3bd8..c62f6da012c1 100644 --- a/core/java/android/hardware/camera2/params/VendorTagDescriptor.java +++ b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java @@ -36,13 +36,7 @@ private VendorTagDescriptor(Parcel source) { new Parcelable.Creator() { @Override public VendorTagDescriptor createFromParcel(Parcel source) { - try { - VendorTagDescriptor vendorDescriptor = new VendorTagDescriptor(source); - return vendorDescriptor; - } catch (Exception e) { - Log.e(TAG, "Exception creating VendorTagDescriptor from parcel", e); - return null; - } + return new VendorTagDescriptor(source); } @Override diff --git a/core/java/android/hardware/camera2/params/VendorTagDescriptorCache.java b/core/java/android/hardware/camera2/params/VendorTagDescriptorCache.java index 450b70bcdcdc..8d7615c98662 100644 --- a/core/java/android/hardware/camera2/params/VendorTagDescriptorCache.java +++ b/core/java/android/hardware/camera2/params/VendorTagDescriptorCache.java @@ -36,13 +36,7 @@ private VendorTagDescriptorCache(Parcel source) { new Parcelable.Creator() { @Override public VendorTagDescriptorCache createFromParcel(Parcel source) { - try { - VendorTagDescriptorCache vendorDescriptorCache = new VendorTagDescriptorCache(source); - return vendorDescriptorCache; - } catch (Exception e) { - Log.e(TAG, "Exception creating VendorTagDescriptorCache from parcel", e); - return null; - } + return new VendorTagDescriptorCache(source); } @Override diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index cfacd5d97bcb..0fa4ca8a574b 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -61,9 +61,6 @@ public final class DisplayManager { * {@link #EXTRA_WIFI_DISPLAY_STATUS} extra. *

* This broadcast is only sent to registered receivers and can only be sent by the system. - *

- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission is required to - * receive this broadcast. *

* @hide */ diff --git a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java index df13ade2bf5e..bd25b8f2ad88 100644 --- a/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java +++ b/core/java/android/hardware/location/GeofenceHardwareRequestParcelable.java @@ -16,9 +16,9 @@ package android.hardware.location; +import android.os.BadParcelableException; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; /** * Geofence Hardware Request used for internal location services communication. @@ -139,11 +139,8 @@ public String toString() { @Override public GeofenceHardwareRequestParcelable createFromParcel(Parcel parcel) { int geofenceType = parcel.readInt(); - if(geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) { - Log.e( - "GeofenceHardwareRequest", - String.format("Invalid Geofence type: %d", geofenceType)); - return null; + if (geofenceType != GeofenceHardwareRequest.GEOFENCE_TYPE_CIRCLE) { + throw new BadParcelableException("Invalid Geofence type: " + geofenceType); } GeofenceHardwareRequest request = GeofenceHardwareRequest.createCircularGeofence( diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 53a5785f7c76..23f4c6301ec1 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -107,6 +107,34 @@ boolean isOpen() { } } + /** + * This is meant to be called by UsbRequest's queue() in order to synchronize on + * UsbDeviceConnection's mLock to prevent the connection being closed while queueing. + */ + /* package */ boolean queueRequest(UsbRequest request, ByteBuffer buffer, int length) { + synchronized (mLock) { + if (!isOpen()) { + return false; + } + + return request.queueIfConnectionOpen(buffer, length); + } + } + + /** + * This is meant to be called by UsbRequest's queue() in order to synchronize on + * UsbDeviceConnection's mLock to prevent the connection being closed while queueing. + */ + /* package */ boolean queueRequest(UsbRequest request, @Nullable ByteBuffer buffer) { + synchronized (mLock) { + if (!isOpen()) { + return false; + } + + return request.queueIfConnectionOpen(buffer); + } + } + /** * Releases all system resources related to the device. * Once the object is closed it cannot be used again. diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index 473df712e3f9..c5573214048c 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -113,11 +113,13 @@ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint) * Releases all resources related to this request. */ public void close() { - if (mNativeContext != 0) { - mEndpoint = null; - mConnection = null; - native_close(); - mCloseGuard.close(); + synchronized (mLock) { + if (mNativeContext != 0) { + mEndpoint = null; + mConnection = null; + native_close(); + mCloseGuard.close(); + } } } @@ -191,10 +193,32 @@ public void setClientData(Object data) { */ @Deprecated public boolean queue(ByteBuffer buffer, int length) { + UsbDeviceConnection connection = mConnection; + if (connection == null) { + // The expected exception by CTS Verifier - USB Device test + throw new NullPointerException("invalid connection"); + } + + // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent + // the connection being closed while queueing. + return connection.queueRequest(this, buffer, length); + } + + /** + * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over + * there, to prevent the connection being closed while queueing. + */ + /* package */ boolean queueIfConnectionOpen(ByteBuffer buffer, int length) { + UsbDeviceConnection connection = mConnection; + if (connection == null || !connection.isOpen()) { + // The expected exception by CTS Verifier - USB Device test + throw new NullPointerException("invalid connection"); + } + boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT); boolean result; - if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P + if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P && length > MAX_USBFS_BUFFER_SIZE) { length = MAX_USBFS_BUFFER_SIZE; } @@ -243,6 +267,28 @@ public boolean queue(ByteBuffer buffer, int length) { * @return true if the queueing operation succeeded */ public boolean queue(@Nullable ByteBuffer buffer) { + UsbDeviceConnection connection = mConnection; + if (connection == null) { + // The expected exception by CTS Verifier - USB Device test + throw new IllegalStateException("invalid connection"); + } + + // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent + // the connection being closed while queueing. + return connection.queueRequest(this, buffer); + } + + /** + * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over + * there, to prevent the connection being closed while queueing. + */ + /* package */ boolean queueIfConnectionOpen(@Nullable ByteBuffer buffer) { + UsbDeviceConnection connection = mConnection; + if (connection == null || !connection.isOpen()) { + // The expected exception by CTS Verifier - USB Device test + throw new IllegalStateException("invalid connection"); + } + // Request need to be initialized Preconditions.checkState(mNativeContext != 0, "request is not initialized"); @@ -260,7 +306,7 @@ public boolean queue(@Nullable ByteBuffer buffer) { mIsUsingNewQueue = true; wasQueued = native_queue(null, 0, 0); } else { - if (mConnection.getContext().getApplicationInfo().targetSdkVersion + if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P) { // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE, @@ -363,11 +409,12 @@ public boolean queue(@Nullable ByteBuffer buffer) { * @return true if cancelling succeeded */ public boolean cancel() { - if (mConnection == null) { + UsbDeviceConnection connection = mConnection; + if (connection == null) { return false; } - return mConnection.cancelRequest(this); + return connection.cancelRequest(this); } /** @@ -382,7 +429,8 @@ public boolean cancel() { * @return true if cancelling succeeded. */ /* package */ boolean cancelIfOpen() { - if (mNativeContext == 0 || (mConnection != null && !mConnection.isOpen())) { + UsbDeviceConnection connection = mConnection; + if (mNativeContext == 0 || (connection != null && !connection.isOpen())) { Log.w(TAG, "Detected attempt to cancel a request on a connection which isn't open"); return false; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 1cb4fe8cf4e7..84fc4f78edc4 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -1194,13 +1194,16 @@ private HierarchicalUri(String scheme, Part authority, PathPart path, } static Uri readFrom(Parcel parcel) { - return new HierarchicalUri( - parcel.readString8(), - Part.readFrom(parcel), - PathPart.readFrom(parcel), - Part.readFrom(parcel), - Part.readFrom(parcel) - ); + final String scheme = parcel.readString8(); + final Part authority = Part.readFrom(parcel); + // In RFC3986 the path should be determined based on whether there is a scheme or + // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3). + final boolean hasSchemeOrAuthority = + (scheme != null && scheme.length() > 0) || !authority.isEmpty(); + final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel); + final Part query = Part.readFrom(parcel); + final Part fragment = Part.readFrom(parcel); + return new HierarchicalUri(scheme, authority, path, query, fragment); } public int describeContents() { @@ -2259,6 +2262,11 @@ static PathPart readFrom(Parcel parcel) { } } + static PathPart readFrom(boolean hasSchemeOrAuthority, Parcel parcel) { + final PathPart path = readFrom(parcel); + return hasSchemeOrAuthority ? makeAbsolute(path) : path; + } + /** * Creates a path from the encoded string. * diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index e5bab6fc9230..5a4b22b8a91b 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -443,6 +443,7 @@ public static Parcel obtain() { */ public final void recycle() { if (DEBUG_RECYCLE) mStack = null; + mClassCookies = null; freeBuffer(); final Parcel[] pool; diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java index 6adba63f42ce..485d43066b0f 100644 --- a/core/java/android/os/WorkSource.java +++ b/core/java/android/os/WorkSource.java @@ -129,7 +129,7 @@ public WorkSource(int uid, @NonNull String packageName) { mNames = in.createStringArray(); int numChains = in.readInt(); - if (numChains > 0) { + if (numChains >= 0) { mChains = new ArrayList<>(numChains); in.readParcelableList(mChains, WorkChain.class.getClassLoader()); } else { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a65a90677d9a..1bcc70a9e274 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10316,6 +10316,123 @@ public static boolean putFloatForUser(ContentResolver cr, String name, float val */ public static final String GESTURE_NAVBAR_LENGTH = "gesture_navbar_length"; + /** Monet Settings */ + /** + * Monet Theme Engine Switch. + * 1 - Enabled (Default) + * 0 - Disabled + * @hide + */ + public static final String MONET_ENGINE = "monet_engine"; + + /** + * Colourfulness + * Default : 1.0 + * @hide + */ + public static final String MONET_CHROMA = "monet_chroma"; + + /** + * Lightness + * Default : 425.0 + * Min : 1.0 + * Max : 1000.0 + * @hide + */ + public static final String MONET_LIGHTNESS = "monet_lightness"; + + /** + * @hide + */ + public static final String MONET_WALLPAPER_COLOR_PICKER = "monet_wallpaper_color_picker"; + + /** + * @hide + */ + public static final String MONET_KEYGUARD_WALLPAPER_COLOR_PICKER = "monet_keyguard_wallpaper_color_picker"; + + /** Monet System Colors */ + /** + * @hide + */ + public static final String MONET_BASE_ACCENT = "monet_base_accent"; + + /** + * @hide + */ + public static final String MONET_BASE_ACCENT_LIGHT = "monet_base_accent_light"; + + /** + * @hide + */ + public static final String MONET_BASE_ACCENT_SECONDARY = "monet_base_accent_secondary"; + + /** + * @hide + */ + public static final String MONET_BASE_ACCENT_SECONDARY_LIGHT = "monet_base_accent_secondary_light"; + + /** + * @hide + */ + public static final String MONET_BASE_ACCENT_TERTIARY = "monet_base_accent_tertiary"; + + /** + * @hide + */ + public static final String MONET_BASE_ACCENT_TERTIARY_LIGHT = "monet_base_accent_tertiary_light"; + + /** + * @hide + */ + public static final String MONET_BACKGROUND = "monet_background"; + + /** + * @hide + */ + public static final String MONET_BACKGROUND_LIGHT = "monet_background_light"; + + /** + * @hide + */ + public static final String MONET_BACKGROUND_SECONDARY = "monet_background_secondary"; + + /** + * @hide + */ + public static final String MONET_BACKGROUND_SECONDARY_LIGHT = "monet_background_secondary_light"; + + /** Monet Keyguard Colors */ + /** + * @hide + */ + public static final String MONET_BASE_KEYGUARD_ACCENT = "monet_base_keyguard_accent"; + + /** + * @hide + */ + public static final String MONET_BASE_KEYGUARD_ACCENT_LIGHT = "monet_base_keyguard_accent_light"; + + /** + * @hide + */ + public static final String MONET_KEYGUARD_BACKGROUND = "monet_keyguard_background"; + + /** + * @hide + */ + public static final String MONET_KEYGUARD_BACKGROUND_LIGHT = "monet_keyguard_background_light"; + + /** + * @hide + */ + public static final String MONET_KEYGUARD_BACKGROUND_SECONDARY = "monet_keyguard_background_secondary"; + + /** + * @hide + */ + public static final String MONET_KEYGUARD_BACKGROUND_SECONDARY_LIGHT = "monet_keyguard_background_secondary_light"; + /** * Current provider of proximity-based sharing services. * Default value in @string/config_defaultNearbySharingComponent. diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java index 7ed733cb4f4c..9d648a6995fb 100644 --- a/core/java/android/service/gatekeeper/GateKeeperResponse.java +++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java @@ -105,7 +105,7 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mTimeout); } else if (mResponseCode == RESPONSE_OK) { dest.writeInt(mShouldReEnroll ? 1 : 0); - if (mPayload != null) { + if (mPayload != null && mPayload.length > 0) { dest.writeInt(mPayload.length); dest.writeByteArray(mPayload); } else { diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java index cf57e2590c9c..0057d3e872ed 100644 --- a/core/java/android/service/notification/Condition.java +++ b/core/java/android/service/notification/Condition.java @@ -89,6 +89,12 @@ public final class Condition implements Parcelable { public final int flags; public final int icon; + /** + * The maximum string length for any string contained in this condition. + * @hide + */ + public static final int MAX_STRING_LENGTH = 1000; + /** * An object representing the current state of a {@link android.app.AutomaticZenRule}. * @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule @@ -103,16 +109,19 @@ public Condition(Uri id, String summary, String line1, String line2, int icon, if (id == null) throw new IllegalArgumentException("id is required"); if (summary == null) throw new IllegalArgumentException("summary is required"); if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state); - this.id = id; - this.summary = summary; - this.line1 = line1; - this.line2 = line2; + this.id = getTrimmedUri(id); + this.summary = getTrimmedString(summary); + this.line1 = getTrimmedString(line1); + this.line2 = getTrimmedString(line2); this.icon = icon; this.state = state; this.flags = flags; } public Condition(Parcel source) { + // This constructor passes all fields directly into the constructor that takes all the + // fields as arguments; that constructor will trim each of the input strings to + // max length if necessary. this((Uri)source.readParcelable(Condition.class.getClassLoader()), source.readString(), source.readString(), @@ -239,4 +248,25 @@ public Condition[] newArray(int size) { return new Condition[size]; } }; + + /** + * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH. + */ + private static String getTrimmedString(String input) { + if (input != null && input.length() > MAX_STRING_LENGTH) { + return input.substring(0, MAX_STRING_LENGTH); + } + return input; + } + + /** + * Returns a truncated copy of the Uri by trimming the string representation to the maximum + * string length. + */ + private static Uri getTrimmedUri(Uri input) { + if (input != null && input.toString().length() > MAX_STRING_LENGTH) { + return Uri.parse(getTrimmedString(input.toString())); + } + return input; + } } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 28596edff123..b46e94e6e058 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -46,6 +46,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -159,6 +160,7 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_ENABLED = "enabled"; private static final String RULE_ATT_SNOOZING = "snoozing"; private static final String RULE_ATT_NAME = "name"; + private static final String RULE_ATT_PKG = "pkg"; private static final String RULE_ATT_COMPONENT = "component"; private static final String RULE_ATT_CONFIG_ACTIVITY = "configActivity"; private static final String RULE_ATT_ZEN = "zen"; @@ -669,11 +671,11 @@ public static ZenRule readRuleXml(XmlPullParser parser) { rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID); rt.component = safeComponentName(parser, RULE_ATT_COMPONENT); rt.configurationActivity = safeComponentName(parser, RULE_ATT_CONFIG_ACTIVITY); - rt.pkg = (rt.component != null) - ? rt.component.getPackageName() - : (rt.configurationActivity != null) - ? rt.configurationActivity.getPackageName() - : null; + rt.pkg = XmlUtils.readStringAttribute(parser, RULE_ATT_PKG); + if (rt.pkg == null) { + // backfill from component, if present. configActivity is not safe to backfill from + rt.pkg = rt.component != null ? rt.component.getPackageName() : null; + } rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0); rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER); rt.condition = readConditionXml(parser); @@ -695,6 +697,9 @@ public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOExcept out.attribute(null, RULE_ATT_NAME, rule.name); } out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode)); + if (rule.pkg != null) { + out.attribute(null, RULE_ATT_PKG, rule.pkg); + } if (rule.component != null) { out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString()); } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 6f941121771e..b956d1918f7e 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -16,12 +16,14 @@ package android.service.voice; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; import android.hardware.soundtrigger.KeyphraseMetadata; @@ -232,8 +234,10 @@ public class AlwaysOnHotwordDetector { private final Callback mExternalCallback; private final Object mLock = new Object(); private final Handler mHandler; + private final Context mContext; private int mAvailability = STATE_NOT_READY; + private boolean mIsGrantedHotwordPermission; /** * A ModelParamRange is a representation of supported parameter range for a @@ -408,23 +412,37 @@ public static abstract class Callback { public abstract void onRecognitionResumed(); } + private static boolean hasHotwordPermission(Context context) { + return context.checkSelfPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD) + == PackageManager.PERMISSION_GRANTED; + } + + private static boolean hasRecordAudioPermission(Context context) { + return context.checkSelfPermission(Manifest.permission.RECORD_AUDIO) + == PackageManager.PERMISSION_GRANTED; + } + /** + * @param context The context to check permission * @param text The keyphrase text to get the detector for. * @param locale The java locale for the detector. * @param callback A non-null Callback for receiving the recognition events. + * @param keyphraseEnrollmentInfo The Enrollment info of key phrase * @param modelManagementService A service that allows management of sound models. * @hide */ - public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback, + public AlwaysOnHotwordDetector(Context context, String text, Locale locale, Callback callback, KeyphraseEnrollmentInfo keyphraseEnrollmentInfo, IVoiceInteractionManagerService modelManagementService) { mText = text; + mContext = context; mLocale = locale; mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo; mExternalCallback = callback; mHandler = new MyHandler(); mInternalCallback = new SoundTriggerListener(mHandler); mModelManagementService = modelManagementService; + mIsGrantedHotwordPermission = hasHotwordPermission(mContext); new RefreshAvailabiltyTask().execute(); } @@ -477,6 +495,11 @@ private int getSupportedRecognitionModesLocked() { @AudioCapabilities public int getSupportedAudioCapabilities() { if (DBG) Slog.d(TAG, "getSupportedAudioCapabilities()"); + + if (!mIsGrantedHotwordPermission) { + return 0; + } + synchronized (mLock) { return getSupportedAudioCapabilitiesLocked(); } @@ -515,6 +538,12 @@ private int getSupportedAudioCapabilitiesLocked() { */ public boolean startRecognition(@RecognitionFlags int recognitionFlags) { if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")"); + + if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) { + throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD " + + "permissions to access the detector."); + } + synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("startRecognition called on an invalid detector"); @@ -545,6 +574,12 @@ public boolean startRecognition(@RecognitionFlags int recognitionFlags) { */ public boolean stopRecognition() { if (DBG) Slog.d(TAG, "stopRecognition()"); + + if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) { + throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD " + + "permissions to access the detector."); + } + synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("stopRecognition called on an invalid detector"); @@ -582,6 +617,10 @@ public int setParameter(@ModelParams int modelParam, int value) { Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")"); } + if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) { + return SoundTrigger.STATUS_INVALID_OPERATION; + } + synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("setParameter called on an invalid detector"); @@ -609,6 +648,10 @@ public int getParameter(@ModelParams int modelParam) { Slog.d(TAG, "getParameter(" + modelParam + ")"); } + if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) { + return MODEL_PARAM_THRESHOLD_FACTOR; + } + synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("getParameter called on an invalid detector"); @@ -634,6 +677,10 @@ public ModelParamRange queryParameter(@ModelParams int modelParam) { Slog.d(TAG, "queryParameter(" + modelParam + ")"); } + if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) { + return null; + } + synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("queryParameter called on an invalid detector"); @@ -742,8 +789,8 @@ void invalidate() { */ void onSoundModelsChanged() { synchronized (mLock) { - if (mAvailability == STATE_INVALID - || mAvailability == STATE_HARDWARE_UNAVAILABLE) { + if (mAvailability == STATE_INVALID || mAvailability == STATE_HARDWARE_UNAVAILABLE + || !hasRecordAudioPermission(mContext)) { Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config"); return; } @@ -962,6 +1009,10 @@ public Void doInBackground(Void... params) { * @return The initial availability without checking the enrollment status. */ private int internalGetInitialAvailability() { + if (!mIsGrantedHotwordPermission) { + return STATE_HARDWARE_UNAVAILABLE; + } + synchronized (mLock) { // This detector has already been invalidated. if (mAvailability == STATE_INVALID) { diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 45d3465fdae8..a56d40790dbf 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -318,7 +318,7 @@ public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( synchronized (mLock) { // Allow only one concurrent recognition via the APIs. safelyShutdownHotwordDetector(); - mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, + mHotwordDetector = new AlwaysOnHotwordDetector(this, keyphrase, locale, callback, mKeyphraseEnrollmentInfo, mSystemService); } return mHotwordDetector; diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java index 077115769374..539cade06e7c 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java @@ -75,6 +75,11 @@ public class ApkSignatureSchemeV2Verifier { private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a; + /** + * The maximum number of signers supported by the v2 APK signature scheme. + */ + private static final int MAX_V2_SIGNERS = 10; + /** * Returns {@code true} if the provided APK contains an APK Signature Scheme V2 signature. * @@ -183,6 +188,11 @@ private static VerifiedSigner verify( } while (signers.hasRemaining()) { signerCount++; + if (signerCount > MAX_V2_SIGNERS) { + throw new SecurityException( + "APK Signature Scheme v2 only supports a maximum of " + MAX_V2_SIGNERS + + " signers"); + } try { ByteBuffer signer = getLengthPrefixedSlice(signers); X509Certificate[] certs = verifySigner(signer, contentDigests, certFactory); diff --git a/core/java/android/util/jar/StrictJarVerifier.java b/core/java/android/util/jar/StrictJarVerifier.java index 45254908c5c9..a6aca330d323 100644 --- a/core/java/android/util/jar/StrictJarVerifier.java +++ b/core/java/android/util/jar/StrictJarVerifier.java @@ -78,6 +78,11 @@ class StrictJarVerifier { "SHA1", }; + /** + * The maximum number of signers supported by the JAR signature scheme. + */ + private static final int MAX_JAR_SIGNERS = 10; + private final String jarName; private final StrictJarManifest manifest; private final HashMap metaEntries; @@ -293,10 +298,16 @@ synchronized boolean readCertificates() { return false; } + int signerCount = 0; Iterator it = metaEntries.keySet().iterator(); while (it.hasNext()) { String key = it.next(); if (key.endsWith(".DSA") || key.endsWith(".RSA") || key.endsWith(".EC")) { + if (++signerCount > MAX_JAR_SIGNERS) { + throw new SecurityException( + "APK Signature Scheme v1 only supports a maximum of " + MAX_JAR_SIGNERS + + " signers"); + } verifyCertificate(key); it.remove(); } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 0410c9024dcb..819e89b67b38 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -336,11 +336,12 @@ interface IWindowSession { * an input channel where the client can receive input. */ void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window, - in IBinder hostInputToken, int flags, int type, out InputChannel outInputChannel); + in IBinder hostInputToken, int flags, int privateFlags, int type, + out InputChannel outInputChannel); /** * Update the flags on an input channel associated with a particular surface. */ void updateInputChannel(in IBinder channelToken, int displayId, in SurfaceControl surface, - int flags, in Region region); + int flags, int privateFlags, in Region region); } diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java index 71d26b8880f7..b3cf78c5157f 100644 --- a/core/java/android/view/InputWindowHandle.java +++ b/core/java/android/view/InputWindowHandle.java @@ -82,6 +82,9 @@ public final class InputWindowHandle { // Input event dispatching is paused. public boolean paused; + // Window is trusted overlay. + public boolean trustedOverlay; + // Id of process and user that owns the window. public int ownerPid; public int ownerUid; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 87b2f4b46df7..0dc7f5ad26fb 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -42,6 +42,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.gui.DropInputMode; import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayedContentSample; import android.hardware.display.DisplayedContentSamplingAttributes; @@ -49,7 +50,6 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; -import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import android.util.SparseIntArray; @@ -139,7 +139,10 @@ private static native void nativeSetBackgroundBlurRadius(long transactionObj, lo int blurRadius); private static native void nativeSetLayerStack(long transactionObj, long nativeObject, int layerStack); - + private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject, + boolean isTrustedOverlay); + private static native void nativeSetDropInputMode( + long transactionObj, long nativeObject, int flags); private static native boolean nativeClearContentFrameStats(long nativeObject); private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats); private static native boolean nativeClearAnimationFrameStats(); @@ -3037,6 +3040,28 @@ public Transaction setFrameRate(@NonNull SurfaceControl sc, return this; } + /** + * Sets the trusted overlay state on this SurfaceControl and it is inherited to all the + * children. The caller must hold the ACCESS_SURFACE_FLINGER permission. + * @hide + */ + public Transaction setTrustedOverlay(SurfaceControl sc, boolean isTrustedOverlay) { + checkPreconditions(sc); + nativeSetTrustedOverlay(mNativeObject, sc.mNativeObject, isTrustedOverlay); + return this; + } + + /** + * Sets the input event drop mode on this SurfaceControl and its children. The caller must + * hold the ACCESS_SURFACE_FLINGER permission. See {@code InputEventDropMode}. + * @hide + */ + public Transaction setDropInputMode(SurfaceControl sc, @DropInputMode int mode) { + checkPreconditions(sc); + nativeSetDropInputMode(mNativeObject, sc.mNativeObject, mode); + return this; + } + /** * Merge the other transaction into this transaction, clearing the * other transaction as if it had been applied. diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 1059c8ad44c2..220b83e7a355 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1237,6 +1237,7 @@ public static class LayoutParams extends ViewGroup.LayoutParams implements Parce public static final int TYPE_SYSTEM_FINGERPRINT_HIGH_LIGHT = FIRST_SYSTEM_WINDOW + 44; /** + * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; @@ -2050,6 +2051,11 @@ public static boolean isSystemAlertWindowType(@WindowType int type) { */ public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000; + /** + * Flag to indicate that the window is a trusted overlay. + * @hide + */ + public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000; /** * An internal annotation for flags that can be specified to {@link #softInputMode}. * @@ -2958,6 +2964,20 @@ public void setFitInsetsIgnoringVisibility(boolean ignore) { privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED; } + /** + * Specifies that the window should be considered a trusted system overlay. Trusted system + * overlays are ignored when considering whether windows are obscured during input + * dispatch. Requires the {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW} + * permission. + * + * {@see android.view.MotionEvent#FLAG_WINDOW_IS_OBSCURED} + * {@see android.view.MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED} + * @hide + */ + public void setTrustedOverlay() { + privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY; + } + /** * @return the insets types that this window is avoiding overlapping. */ diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index f0006d988163..13f26f5a7fb6 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -115,7 +115,8 @@ protected void setTouchRegion(IBinder window, @Nullable Region region) { if (state.mInputChannelToken != null) { try { mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, - state.mSurfaceControl, state.mParams.flags, state.mInputRegion); + state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags, + state.mInputRegion); } catch (RemoteException e) { Log.e(TAG, "Failed to update surface input channel: ", e); } @@ -144,7 +145,7 @@ public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attr WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) { try { mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags, - attrs.type, outInputChannel); + attrs.privateFlags, attrs.type, outInputChannel); } catch (RemoteException e) { Log.e(TAG, "Failed to grant input to surface: ", e); } @@ -274,7 +275,7 @@ public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs, && state.mInputChannelToken != null) { try { mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc, - attrs.flags, state.mInputRegion); + attrs.flags, attrs.privateFlags, state.mInputRegion); } catch (RemoteException e) { Log.e(TAG, "Failed to update surface input channel: ", e); } @@ -445,12 +446,13 @@ public void reportSystemGestureExclusionChanged(android.view.IWindow window, @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, - IBinder hostInputToken, int flags, int type, InputChannel outInputChannel) { + IBinder hostInputToken, int flags, int privateFlags, int type, + InputChannel outInputChannel) { } @Override public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface, - int flags, Region region) { + int flags, int privateFlags, Region region) { } @Override diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 5f8b13b5b548..7b2ebde70e5f 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -2957,7 +2957,7 @@ public Map> getShortcutInputMethodsAnd @UnsupportedAppUsage public int getInputMethodWindowVisibleHeight() { try { - return mService.getInputMethodWindowVisibleHeight(); + return mService.getInputMethodWindowVisibleHeight(mClient); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index a9b2c4df255f..6693b937a6e5 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -562,6 +562,12 @@ public void visitUris(@NonNull Consumer visitor) { mActions.get(i).visitUris(visitor); } } + if (mLandscape != null) { + mLandscape.visitUris(visitor); + } + if (mPortrait != null) { + mPortrait.visitUris(visitor); + } } private static void visitIconUri(Icon icon, @NonNull Consumer visitor) { @@ -1674,6 +1680,11 @@ public boolean prefersAsyncApply() { public int getActionTag() { return VIEW_GROUP_ACTION_ADD_TAG; } + + @Override + public final void visitUris(@NonNull Consumer visitor) { + mNestedViews.visitUris(visitor); + } } /** diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index cee224b3372f..118d4c6adc5d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -16,6 +16,8 @@ package com.android.internal.app; +import static android.content.ContentProvider.getUserIdFromUri; + import static java.lang.annotation.RetentionPolicy.SOURCE; import android.animation.Animator; @@ -148,6 +150,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * The Chooser Activity handles intent resolution specifically for sharing intents - @@ -1296,7 +1299,7 @@ private ViewGroup displayTextContentPreview(Intent targetIntent, LayoutInflater ImageView previewThumbnailView = contentPreviewLayout.findViewById( R.id.content_preview_thumbnail); - if (previewThumbnail == null) { + if (!validForContentPreview(previewThumbnail)) { previewThumbnailView.setVisibility(View.GONE); } else { mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false); @@ -1323,6 +1326,10 @@ private ViewGroup displayImageContentPreview(Intent targetIntent, LayoutInflater String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0); } else { ContentResolver resolver = getContentResolver(); @@ -1330,7 +1337,7 @@ private ViewGroup displayImageContentPreview(Intent targetIntent, LayoutInflater List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); List imageUris = new ArrayList<>(); for (Uri uri : uris) { - if (isImageType(resolver.getType(uri))) { + if (validForContentPreview(uri) && isImageType(resolver.getType(uri))) { imageUris.add(uri); } } @@ -1437,9 +1444,16 @@ private ViewGroup displayFileContentPreview(Intent targetIntent, LayoutInflater String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } loadFileUriIntoView(uri, contentPreviewLayout); } else { List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + uris = uris.stream() + .filter(ChooserActivity::validForContentPreview) + .collect(Collectors.toList()); int uriCount = uris.size(); if (uriCount == 0) { @@ -1493,6 +1507,24 @@ private void loadFileUriIntoView(final Uri uri, final View parent) { } } + /** + * Indicate if the incoming content URI should be allowed. + * + * @param uri the uri to test + * @return true if the URI is allowed for content preview + */ + private static boolean validForContentPreview(Uri uri) throws SecurityException { + if (uri == null) { + return false; + } + int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT); + if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) { + Log.e(TAG, "dropped invalid content URI belonging to user " + userId); + return false; + } + return true; + } + @VisibleForTesting protected boolean isImageType(String mimeType) { return mimeType != null && mimeType.startsWith("image/"); diff --git a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java index ce2d229d41b3..33209e110123 100644 --- a/core/java/com/android/internal/app/HarmfulAppWarningActivity.java +++ b/core/java/com/android/internal/app/HarmfulAppWarningActivity.java @@ -16,6 +16,8 @@ package com.android.internal.app; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -27,6 +29,7 @@ import android.util.Log; import android.view.View; import android.widget.TextView; + import com.android.internal.R; /** @@ -48,6 +51,7 @@ public class HarmfulAppWarningActivity extends AlertActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); final Intent intent = getIntent(); mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME); mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 1270185e1ea5..998000c19cd0 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -19,6 +19,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_PROFILES; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.PermissionChecker.PID_UNKNOWN; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; import android.annotation.Nullable; import android.annotation.StringRes; @@ -69,7 +70,9 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.Window; import android.view.WindowInsets; +import android.view.WindowManager; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.Button; @@ -101,7 +104,6 @@ import java.util.Objects; import java.util.Set; - /** * This activity is displayed when the system attempts to start an Intent for * which there is more than one matching activity, allowing the user to decide @@ -822,6 +824,8 @@ protected void onRestart() { @Override protected void onStart() { super.onStart(); + + this.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); if (shouldShowTabs()) { mWorkProfileStateReceiver = createWorkProfileStateReceiver(); registerWorkProfileStateReceiver(); @@ -849,6 +853,12 @@ private void registerWorkProfileStateReceiver() { @Override protected void onStop() { super.onStop(); + + final Window window = this.getWindow(); + final WindowManager.LayoutParams attrs = window.getAttributes(); + attrs.privateFlags &= ~SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + window.setAttributes(attrs); + if (mRegistered) { mPersonalPackageMonitor.unregister(); if (mWorkPackageMonitor != null) { @@ -1223,9 +1233,6 @@ protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { } if (target != null) { - if (intent != null && isLaunchingTargetInOtherProfile()) { - prepareIntentForCrossProfileLaunch(intent); - } safelyStartActivity(target); // Rely on the ActivityManager to pop up a dialog regarding app suspension @@ -1238,15 +1245,6 @@ protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { return true; } - private void prepareIntentForCrossProfileLaunch(Intent intent) { - intent.fixUris(UserHandle.myUserId()); - } - - private boolean isLaunchingTargetInOtherProfile() { - return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier() - != UserHandle.myUserId(); - } - @VisibleForTesting public void safelyStartActivity(TargetInfo cti) { // We're dispatching intents that might be coming from legacy apps, so diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java index fe0e7d012262..cbbfbdd88a6c 100644 --- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java +++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java @@ -178,6 +178,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user if (ENABLE_CHOOSER_DELEGATE) { return activity.startAsCallerImpl(mResolvedIntent, options, false, userId); } else { + TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId); activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId); return true; } @@ -185,6 +186,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user @Override public boolean startAsUser(Activity activity, Bundle options, UserHandle user) { + TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier()); activity.startActivityAsUser(mResolvedIntent, options, user); return false; } diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java index 900e18d468bb..9d057b34363e 100644 --- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java +++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java @@ -230,6 +230,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user } intent.setComponent(mChooserTarget.getComponentName()); intent.putExtras(mChooserTarget.getIntentExtras()); + TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId); // Important: we will ignore the target security checks in ActivityManager // if and only if the ChooserTarget's target package is the same package diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java index f56ab17cb059..7bb7ddc65c6d 100644 --- a/core/java/com/android/internal/app/chooser/TargetInfo.java +++ b/core/java/com/android/internal/app/chooser/TargetInfo.java @@ -130,4 +130,15 @@ public interface TargetInfo { * @return true if this target should be pinned to the front by the request of the user */ boolean isPinned(); + + /** + * Fix the URIs in {@code intent} if cross-profile sharing is required. This should be called + * before launching the intent as another user. + */ + static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) { + final int currentUserId = UserHandle.myUserId(); + if (targetUserId != currentUserId) { + intent.fixUris(currentUserId); + } + } } diff --git a/core/java/com/android/internal/infra/AndroidFuture.java b/core/java/com/android/internal/infra/AndroidFuture.java index 9f15d8991fa7..84391c169941 100644 --- a/core/java/com/android/internal/infra/AndroidFuture.java +++ b/core/java/com/android/internal/infra/AndroidFuture.java @@ -16,23 +16,21 @@ package com.android.internal.infra; -import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; - import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; -import android.os.Message; +import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; -import android.util.ExceptionUtils; +import android.util.EventLog; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; -import com.android.internal.util.function.pooled.PooledLambda; +import java.lang.reflect.Constructor; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -75,14 +73,16 @@ public class AndroidFuture extends CompletableFuture implements Parcelable private static final boolean DEBUG = false; private static final String LOG_TAG = AndroidFuture.class.getSimpleName(); + private static final Executor DIRECT_EXECUTOR = Runnable::run; private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; + private static @Nullable Handler sMainHandler; private final @NonNull Object mLock = new Object(); @GuardedBy("mLock") private @Nullable BiConsumer mListener; @GuardedBy("mLock") private @Nullable Executor mListenerExecutor = DIRECT_EXECUTOR; - private @NonNull Handler mTimeoutHandler = Handler.getMain(); + private @NonNull Handler mTimeoutHandler = getMainHandler(); private final @Nullable IAndroidFuture mRemoteOrigin; public AndroidFuture() { @@ -96,7 +96,7 @@ public AndroidFuture() { // Done if (in.readBoolean()) { // Failed - completeExceptionally(unparcelException(in)); + completeExceptionally(readThrowable(in)); } else { // Success complete((T) in.readValue(null)); @@ -108,6 +108,15 @@ public AndroidFuture() { } } + @NonNull + private static Handler getMainHandler() { + // This isn't thread-safe but we are okay with it. + if (sMainHandler == null) { + sMainHandler = new Handler(Looper.getMainLooper()); + } + return sMainHandler; + } + /** * Create a completed future with the given value. * @@ -236,9 +245,7 @@ private void callListenerAsync(BiConsumer listener if (mListenerExecutor == DIRECT_EXECUTOR) { callListener(listener, res, err); } else { - mListenerExecutor.execute(PooledLambda - .obtainRunnable(AndroidFuture::callListener, listener, res, err) - .recycleOnUse()); + mListenerExecutor.execute(() -> callListener(listener, res, err)); } } @@ -260,7 +267,8 @@ static void callListener( } else { // listener exception-case threw // give up on listener but preserve the original exception when throwing up - throw ExceptionUtils.appendCause(t, err); + t.addSuppressed(err); + throw t; } } } catch (Throwable t2) { @@ -272,9 +280,7 @@ static void callListener( /** @inheritDoc */ //@Override //TODO uncomment once java 9 APIs are exposed to frameworks public AndroidFuture orTimeout(long timeout, @NonNull TimeUnit unit) { - Message msg = PooledLambda.obtainMessage(AndroidFuture::triggerTimeout, this); - msg.obj = this; - mTimeoutHandler.sendMessageDelayed(msg, unit.toMillis(timeout)); + mTimeoutHandler.postDelayed(this::triggerTimeout, this, unit.toMillis(timeout)); return this; } @@ -507,7 +513,7 @@ public void writeToParcel(Parcel dest, int flags) { result = get(); } catch (Throwable t) { dest.writeBoolean(true); - parcelException(dest, unwrapExecutionException(t)); + writeThrowable(dest, unwrapExecutionException(t)); return; } dest.writeBoolean(false); @@ -545,45 +551,75 @@ Throwable unwrapExecutionException(Throwable t) { * Alternative to {@link Parcel#writeException} that stores the stack trace, in a * way consistent with the binder IPC exception propagation behavior. */ - private static void parcelException(Parcel p, @Nullable Throwable t) { - p.writeBoolean(t == null); - if (t == null) { + private static void writeThrowable(@NonNull Parcel parcel, @Nullable Throwable throwable) { + boolean hasThrowable = throwable != null; + parcel.writeBoolean(hasThrowable); + if (!hasThrowable) { + return; + } + + boolean isFrameworkParcelable = throwable instanceof Parcelable + && throwable.getClass().getClassLoader() == Parcelable.class.getClassLoader(); + parcel.writeBoolean(isFrameworkParcelable); + if (isFrameworkParcelable) { + parcel.writeParcelable((Parcelable) throwable, + Parcelable.PARCELABLE_WRITE_RETURN_VALUE); return; } - p.writeInt(Parcel.getExceptionCode(t)); - p.writeString(t.getClass().getName()); - p.writeString(t.getMessage()); - p.writeStackTrace(t); - parcelException(p, t.getCause()); + parcel.writeString(throwable.getClass().getName()); + parcel.writeString(throwable.getMessage()); + StackTraceElement[] stackTrace = throwable.getStackTrace(); + StringBuilder stackTraceBuilder = new StringBuilder(); + int truncatedStackTraceLength = Math.min(stackTrace != null ? stackTrace.length : 0, 5); + for (int i = 0; i < truncatedStackTraceLength; i++) { + if (i > 0) { + stackTraceBuilder.append('\n'); + } + stackTraceBuilder.append("\tat ").append(stackTrace[i]); + } + parcel.writeString(stackTraceBuilder.toString()); + writeThrowable(parcel, throwable.getCause()); } /** - * @see #parcelException + * @see #writeThrowable */ - private static @Nullable Throwable unparcelException(Parcel p) { - if (p.readBoolean()) { + private static @Nullable Throwable readThrowable(@NonNull Parcel parcel) { + final boolean hasThrowable = parcel.readBoolean(); + if (!hasThrowable) { return null; } - int exCode = p.readInt(); - String cls = p.readString(); - String msg = p.readString(); - String stackTrace = p.readInt() > 0 ? p.readString() : "\t"; - msg += "\n" + stackTrace; - - Exception ex = p.createExceptionOrNull(exCode, msg); - if (ex == null) { - ex = new RuntimeException(cls + ": " + msg); + boolean isFrameworkParcelable = parcel.readBoolean(); + if (isFrameworkParcelable) { + return parcel.readParcelable(Parcelable.class.getClassLoader()); } - ex.setStackTrace(EMPTY_STACK_TRACE); - Throwable cause = unparcelException(p); + String className = parcel.readString(); + String message = parcel.readString(); + String stackTrace = parcel.readString(); + String messageWithStackTrace = message + '\n' + stackTrace; + Throwable throwable; + try { + Class clazz = Class.forName(className, true, Parcelable.class.getClassLoader()); + if (Throwable.class.isAssignableFrom(clazz)) { + Constructor constructor = clazz.getConstructor(String.class); + throwable = (Throwable) constructor.newInstance(messageWithStackTrace); + } else { + android.util.EventLog.writeEvent(0x534e4554, "186530450", -1, ""); + throwable = new RuntimeException(className + ": " + messageWithStackTrace); + } + } catch (Throwable t) { + throwable = new RuntimeException(className + ": " + messageWithStackTrace); + throwable.addSuppressed(t); + } + throwable.setStackTrace(EMPTY_STACK_TRACE); + Throwable cause = readThrowable(parcel); if (cause != null) { - ex.initCause(ex); + throwable.initCause(cause); } - - return ex; + return throwable; } @Override diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java index 167d128a76f8..89869389cb59 100644 --- a/core/java/com/android/internal/infra/ServiceConnector.java +++ b/core/java/com/android/internal/infra/ServiceConnector.java @@ -26,14 +26,11 @@ import android.os.Handler; import android.os.IBinder; import android.os.IInterface; +import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; -import android.text.TextUtils; -import android.util.DebugUtils; import android.util.Log; -import com.android.internal.util.function.pooled.PooledLambda; - import java.io.PrintWriter; import java.util.ArrayDeque; import java.util.ArrayList; @@ -47,7 +44,6 @@ import java.util.function.BiConsumer; import java.util.function.Function; - /** * Takes care of managing a {@link ServiceConnection} and auto-disconnecting from the service upon * a certain timeout. @@ -220,6 +216,7 @@ class Impl extends ArrayDeque> private final @NonNull Queue> mQueue = this; private final @NonNull List> mUnfinishedJobs = new ArrayList<>(); + private final @NonNull Handler mMainHandler = new Handler(Looper.getMainLooper()); private final @NonNull ServiceConnection mServiceConnection = this; private final @NonNull Runnable mTimeoutDisconnect = this; @@ -250,9 +247,8 @@ class Impl extends ArrayDeque> * {@link IInterface}. * Typically this is {@code IMyInterface.Stub::asInterface} */ - public Impl(@NonNull Context context, @NonNull Intent intent, - @Context.BindServiceFlags int bindingFlags, @UserIdInt int userId, - @Nullable Function binderAsInterface) { + public Impl(@NonNull Context context, @NonNull Intent intent, int bindingFlags, + @UserIdInt int userId, @Nullable Function binderAsInterface) { mContext = context; mIntent = intent; mBindingFlags = bindingFlags; @@ -264,7 +260,7 @@ public Impl(@NonNull Context context, @NonNull Intent intent, * {@link Handler} on which {@link Job}s will be called */ protected Handler getJobHandler() { - return Handler.getMain(); + return mMainHandler; } /** @@ -391,8 +387,7 @@ private void enqueue(@NonNull CompletionAwareJob task) { private boolean enqueue(@NonNull Job job) { cancelTimeout(); - return getJobHandler().sendMessage(PooledLambda.obtainMessage( - ServiceConnector.Impl::enqueueJobThread, this, job)); + return getJobHandler().post(() -> enqueueJobThread(job)); } void enqueueJobThread(@NonNull Job job) { @@ -422,7 +417,7 @@ private void cancelTimeout() { if (DEBUG) { logTrace(); } - Handler.getMain().removeCallbacks(mTimeoutDisconnect); + mMainHandler.removeCallbacks(mTimeoutDisconnect); } void completeExceptionally(@NonNull Job job, @NonNull Throwable ex) { @@ -486,7 +481,7 @@ private void scheduleUnbindTimeout() { } long timeout = getAutoDisconnectTimeoutMs(); if (timeout > 0) { - Handler.getMain().postDelayed(mTimeoutDisconnect, timeout); + mMainHandler.postDelayed(mTimeoutDisconnect, timeout); } else if (DEBUG) { Log.i(LOG_TAG, "Not scheduling unbind for permanently bound " + this); } @@ -502,7 +497,7 @@ public void unbind() { logTrace(); } mUnbinding = true; - getJobHandler().sendMessage(PooledLambda.obtainMessage(Impl::unbindJobThread, this)); + getJobHandler().post(this::unbindJobThread); } void unbindJobThread() { @@ -659,10 +654,7 @@ private String stateToString() { } private void logTrace() { - Log.i(LOG_TAG, - TextUtils.join(" -> ", - DebugUtils.callersWithin(ServiceConnector.class, /* offset= */ 1)) - + "(" + this + ")"); + Log.i(LOG_TAG, "See stacktrace", new Throwable()); } /** diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java index 4ce6f609ef73..fdf0e9046eef 100644 --- a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java +++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java @@ -17,6 +17,7 @@ package com.android.internal.notification; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; public final class NotificationAccessConfirmationActivityContract { @@ -25,13 +26,14 @@ public final class NotificationAccessConfirmationActivityContract { "com.android.settings.notification.NotificationAccessConfirmationActivity"); public static final String EXTRA_USER_ID = "user_id"; public static final String EXTRA_COMPONENT_NAME = "component_name"; - public static final String EXTRA_PACKAGE_TITLE = "package_title"; - public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) { + /** + * Creates a launcher intent for NotificationAccessConfirmationActivity. + */ + public static Intent launcherIntent(Context context, int userId, ComponentName component) { return new Intent() .setComponent(COMPONENT_NAME) .putExtra(EXTRA_USER_ID, userId) - .putExtra(EXTRA_COMPONENT_NAME, component) - .putExtra(EXTRA_PACKAGE_TITLE, packageTitle); + .putExtra(EXTRA_COMPONENT_NAME, component); } } diff --git a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl index 8e454db4cb04..a8003a1169e9 100644 --- a/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl +++ b/core/java/com/android/internal/policy/IKeyguardStateCallback.aidl @@ -16,7 +16,7 @@ package com.android.internal.policy; interface IKeyguardStateCallback { - void onShowingStateChanged(boolean showing); + void onShowingStateChanged(boolean showing, int userId); void onSimSecureStateChanged(boolean simSecure); void onInputRestrictedStateChanged(boolean inputRestricted); void onTrustedChanged(boolean trusted); diff --git a/core/java/com/android/internal/util/corvus/PixelPropsUtils.java b/core/java/com/android/internal/util/corvus/PixelPropsUtils.java index f691b57ebd5f..0b6b4861bee4 100644 --- a/core/java/com/android/internal/util/corvus/PixelPropsUtils.java +++ b/core/java/com/android/internal/util/corvus/PixelPropsUtils.java @@ -66,6 +66,42 @@ public class PixelPropsUtils { "com.google.android.googlequicksearchbox" }; + private static final Map propsToChangeROG1; + private static final String[] packagesToChangeROG1 = { + "com.dts.freefireth", + "com.dts.freefiremax", + "com.madfingergames.legends" + }; + + private static final Map propsToChangeXP5; + private static final String[] packagesToChangeXP5 = { + "com.activision.callofduty.shooter", + "com.tencent.tmgp.kr.codm", + "com.garena.game.codm", + "com.vng.codmvn" + }; + + private static final Map propsToChangeOP8P; + private static final String[] packagesToChangeOP8P = { + "com.tencent.ig", + "com.pubg.krmobile", + "com.pubg.newstate", + "com.vng.pubgmobile", + "com.rekoo.pubgm", + "com.tencent.tmgp.pubgmhd", + "com.riotgames.league.wildrift", + "com.riotgames.league.wildrifttw", + "com.riotgames.league.wildriftvn", + "com.netease.lztgglobal", + "com.epicgames.fortnite", + "com.epicgames.portal" + }; + + private static final Map propsToChangeK30U; + private static final String[] packagesToChangeK30U = { + "com.pubg.imobile" + }; + static { propsToChange = new HashMap<>(); propsToChange.put("BRAND", "google"); @@ -88,6 +124,17 @@ public class PixelPropsUtils { propsToChangePixel3XL.put("PRODUCT", "crosshatch"); propsToChangePixel3XL.put("MODEL", "Pixel 3 XL"); propsToChangePixel3XL.put("FINGERPRINT", "google/crosshatch/crosshatch:11/RQ3A.210605.005/7349499:user/release-keys"); + propsToChangeROG1 = new HashMap<>(); + propsToChangeROG1.put("MODEL", "ASUS_Z01QD"); + propsToChangeROG1.put("MANUFACTURER", "asus"); + propsToChangeXP5 = new HashMap<>(); + propsToChangeXP5.put("MODEL", "SO-52A"); + propsToChangeOP8P = new HashMap<>(); + propsToChangeOP8P.put("MODEL", "IN2020"); + propsToChangeOP8P.put("MANUFACTURER", "OnePlus"); + propsToChangeK30U = new HashMap<>(); + propsToChangeK30U.put("MODEL", "M2006J10C"); + propsToChangeK30U.put("MANUFACTURER", "Xiaomi"); } public static void setProps(String packageName) { @@ -125,10 +172,40 @@ public static void setProps(String packageName) { } } // Set proper indexing fingerprint - if (packageName.equals("com.google.android.settings.intelligence")) { + if (packageName.equals("com.google.android.settings.intelligence")) { setPropValue("FINGERPRINT", Build.DATE); } - } + } else { + if (Arrays.asList(packagesToChangeROG1).contains(packageName)) { + if (DEBUG) Log.d(TAG, "Defining props for: " + packageName); + for (Map.Entry prop : propsToChangeROG1.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + setPropValue(key, value); + } + } else if (Arrays.asList(packagesToChangeXP5).contains(packageName)) { + if (DEBUG) Log.d(TAG, "Defining props for: " + packageName); + for (Map.Entry prop : propsToChangeXP5.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + setPropValue(key, value); + } + } else if (Arrays.asList(packagesToChangeOP8P).contains(packageName)) { + if (DEBUG) Log.d(TAG, "Defining props for: " + packageName); + for (Map.Entry prop : propsToChangeOP8P.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + setPropValue(key, value); + } + } else if (Arrays.asList(packagesToChangeK30U).contains(packageName)) { + if (DEBUG) Log.d(TAG, "Defining props for: " + packageName); + for (Map.Entry prop : propsToChangeK30U.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + setPropValue(key, value); + } + } + } private static void setPropValue(String key, Object value) { try { @@ -143,4 +220,5 @@ private static void setPropValue(String key, Object value) { Log.e(TAG, "Failed to set prop " + key, e); } } + } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index a1cbd3fcae79..629d92927237 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -67,7 +67,7 @@ interface IInputMethodManager { void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); // This is kept due to @UnsupportedAppUsage. // TODO(Bug 113914148): Consider removing this. - int getInputMethodWindowVisibleHeight(); + int getInputMethodWindowVisibleHeight(in IInputMethodClient client); void reportActivityView(in IInputMethodClient parentClient, int childDisplayId, in float[] matrixValues); diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp index 79f62cb19db0..81569e0f7b7a 100644 --- a/core/jni/android_hardware_input_InputWindowHandle.cpp +++ b/core/jni/android_hardware_input_InputWindowHandle.cpp @@ -59,6 +59,7 @@ static struct { jfieldID hasFocus; jfieldID hasWallpaper; jfieldID paused; + jfieldID trustedOverlay; jfieldID ownerPid; jfieldID ownerUid; jfieldID inputFeatures; @@ -151,6 +152,7 @@ bool NativeInputWindowHandle::updateInfo() { gInputWindowHandleClassInfo.hasWallpaper); mInfo.paused = env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused); + mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay); mInfo.ownerPid = env->GetIntField(obj, gInputWindowHandleClassInfo.ownerPid); mInfo.ownerUid = env->GetIntField(obj, @@ -329,6 +331,8 @@ int register_android_view_InputWindowHandle(JNIEnv* env) { GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz, "paused", "Z"); + GET_FIELD_ID(gInputWindowHandleClassInfo.trustedOverlay, clazz, "trustedOverlay", "Z"); + GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz, "ownerPid", "I"); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index ae36f8a7b30b..3c704ffb8de7 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -627,6 +627,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb transaction->setShadowRadius(ctrl, shadowRadius); } +static void nativeSetTrustedOverlay(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jboolean isTrustedOverlay) { + auto transaction = reinterpret_cast(transactionObj); + + SurfaceControl* const ctrl = reinterpret_cast(nativeObject); + transaction->setTrustedOverlay(ctrl, isTrustedOverlay); +} + static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jfloat frameRate, jint compatibility) { auto transaction = reinterpret_cast(transactionObj); @@ -663,6 +671,13 @@ static void nativeSetFixedTransformHint(JNIEnv* env, jclass clazz, jlong transac transaction->setFixedTransformHint(ctrl, transformHint); } +static void nativeSetDropInputMode(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jint mode) { + auto transaction = reinterpret_cast(transactionObj); + SurfaceControl* const ctrl = reinterpret_cast(nativeObject); + transaction->setDropInputMode(ctrl, static_cast(mode)); +} + static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) { const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); jlongArray array = env->NewLongArray(displayIds.size()); @@ -1487,6 +1502,7 @@ static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { // ---------------------------------------------------------------------------- static const JNINativeMethod sSurfaceControlMethods[] = { + // clang-format off {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J", (void*)nativeCreate }, {"nativeReadFromParcel", "(Landroid/os/Parcel;)J", @@ -1666,7 +1682,13 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetGlobalShadowSettings }, {"nativeGetHandle", "(J)J", (void*)nativeGetHandle }, - {"nativeSetFixedTransformHint", "(JJI)V", (void*)nativeSetFixedTransformHint}, + {"nativeSetFixedTransformHint", "(JJI)V", + (void*)nativeSetFixedTransformHint}, + {"nativeSetTrustedOverlay", "(JJZ)V", + (void*)nativeSetTrustedOverlay }, + {"nativeSetDropInputMode", "(JJI)V", + (void*)nativeSetDropInputMode}, + // clang-format on }; int register_android_view_SurfaceControl(JNIEnv* env) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 177389b2da69..5a269b891eba 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -96,6 +96,7 @@ + @@ -2575,7 +2576,11 @@ android:protectionLevel="normal" /> + + "Weier" "Toestemming versoek" "Toestemming versoek\nvir rekening %s." + "Toestemming versoek deur %1$s\nvir rekening %2$s" "Jy gebruik hierdie program buite jou werkprofiel" "Jy gebruik tans hierdie program in jou werkprofiel" "Invoermetode" diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index d41868e8c478..670b64e010f0 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1413,6 +1413,7 @@ "ያስተባብሉ" "ፈቃድ ተጠይቋል" \n" ለ%s መለያ ፈቃድ ተጠይቋል" + "ለመለያ %2$s\nበ%1$s የተጠየቀ ፈቃድ።" "ከስራ መገለጫዎ ውጪ ሆነው መተግበሪያ እየተጠቀሙ ነው" "ይህን መተግበሪያ በእርስዎ የስራ መገለጫ ላይ እየተጠቀሙበት ነው" "ግቤት ስልት" diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 4a99ec8021e8..7e5460160a7d 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -1493,6 +1493,7 @@ "رفض" "الإذن مطلوب" "الإذن مطلوب\nللحساب %s." + "طلب تطبيق %1$s الإذن بالدخول\nإلى حساب %2$s." "أنت تستخدم هذا التطبيق خارج ملفك الشخصي للعمل" "أنت تستخدم هذا التطبيق في ملفك الشخصي للعمل" "طريقة الإرسال" diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 2ca98b4c5f22..3573ff5d6eb9 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1413,6 +1413,7 @@ "প্ৰত্যাখ্যান কৰক" "অনুমতি বিচাৰি অনুৰোধ কৰা হৈছে" "%s একাউণ্টৰ বাবে\nঅনুমতি বিচাৰি অনুৰোধ কৰা হৈছে।" + "%1$s%2$s একাউণ্টটো এক্সেছৰ \nঅনুমতি বিচাৰি অনুৰোধ জনাইছে।" "আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ বাহিৰত এই এপটো ব্যৱহাৰ কৰি আছে" "আপুনি আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইলৰ ভিতৰত এই এপটো ব্যৱহাৰ কৰি আছে" "ইনপুট পদ্ধতি" diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 36c293c491c6..52c57cdcd112 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1413,6 +1413,7 @@ "Rədd et" "İcazə tələb olunur" \n" hesabı üçün%s icazə sorğusu göndərildi." + "%1$s\ntərəfindən %2$s hesabı üçün icazə tələb edilib." "Bu tətbiqi iş profilinizdən kənarda istifadə edirsiniz" "Bu tətbiqi iş profilinizdə istifadə edirsiniz" "Daxiletmə metodu" diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index daec63a9d5a5..1399c8fb9f37 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -1433,6 +1433,7 @@ "Odbij" "Zatražena je dozvola" "Zatražena je dozvola\nza nalog %s" + "%1$s traži dozvolu \nza nalog %2$s." "Koristite ovu aplikaciju izvan poslovnog profila" "Koristite ovu aplikaciju na poslovnom profilu" "Metod unosa" diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 220c3520a1db..bd35a675d814 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1453,6 +1453,7 @@ "Адмовіць" "Дазвол запытаны" "Запытаны дазвол\nдля ўліковага запісу %s" + "Праграма \"%1$s\" запытвае дазвол\nдля ўліковага запісу %2$s." "Вы выкарыстоўваеце гэту праграму па-за межамі свайго працоўнага профілю" "Вы выкарыстоўваеце гэту праграму ў сваім працоўным профілі" "Метад уводу" diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 8d3a23c99e3b..5a4dc99e3845 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -1413,6 +1413,7 @@ "Отказване" "Иска се разрешение" "Иска се разрешение\nза профила %s." + "Поискано е разрешение от %1$s\nза профила %2$s." "Използвате това приложение извън служебния си потребителски профил" "Използвате това приложение в служебния си потребителски профил" "Метод на въвеждане" diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index 9462be3f2f44..b91868e8f147 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -1413,6 +1413,7 @@ "অস্বীকার করুন" "অনুমতির অনুরোধ করা হয়েছে" "%sঅ্যাকাউন্টের জন্য\nঅনুমতির অনুরোধ করা হয়েছে৷" + "%2$s অ্যাকাউন্টের জন্য %1$s\n থেকে অনুমতি চাওয়া হয়েছে।" "আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলের বাইরে ব্যবহার করছেন" "আপনি এই অ্যাপ্লিকেশানটি আপনার কর্মস্থলের প্রোফাইলে ব্যবহার করছেন" "ইনপুট পদ্ধতি" diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 7511455fc0ee..2c4f91ee339c 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1433,6 +1433,7 @@ "Odbij" "Upućen zahtjev za odobrenje" "Upućen zahtjev za dozvolu\nza račun %s." + "Odobrenje je zatražila aplikacija %1$s\nza račun %2$s." "Aplikaciju koristite van poslovnog profila" "Aplikaciju koristite u poslovnom profilu" "Način unosa" diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index ca45c00fb8b3..2b18f3f8a731 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1413,6 +1413,7 @@ "Denega" "Permís sol·licitat" "S\'ha sol·licitat permís\nper al compte %s." + "%1$s ha sol·licitat permís\nper accedir al compte %2$s." "Estàs utilitzant aquesta aplicació fora del perfil de treball." "Estàs utilitzant l\'aplicació al perfil de treball." "Mètode d\'introducció de text" diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a5f421390d44..fdbf1f80719c 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1453,6 +1453,7 @@ "Odepřít" "Požadováno oprávnění" "Požadováno oprávnění\npro účet %s." + "Aplikace %1$s požádala o přístup\nk účtu %2$s." "Tuto aplikaci používáte mimo svůj pracovní profil." "Tuto aplikaci používáte v pracovním profilu" "Metoda zadávání dat" diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 09e2ea20cd92..70dfcb2fb354 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -1413,6 +1413,7 @@ "Afvis" "Der er anmodet om tilladelse" "Der er anmodet om tilladelse\nfor kontoen %s." + "%1$s har anmodet om tilladelse\nfor kontoen %2$s." "Du bruger denne app uden for din arbejdsprofil" "Du bruger denne app i din arbejdsprofil" "Inputmetode" diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 627a3ab6a4fd..dfe712e9f42a 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -1413,6 +1413,7 @@ "Ablehnen" "Berechtigung angefordert" "Berechtigung angefordert\nfür Konto %s" + "Berechtigung wurde angefordert von %1$s\nfür das Konto %2$s." "Du verwendest diese App außerhalb deines Arbeitsprofils" "Du verwendest diese App in deinem Arbeitsprofil." "Eingabemethode" diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 9435d34b562e..a8ac541b9840 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1413,6 +1413,7 @@ "Άρνηση" "Απαιτείται άδεια" "Ζητήθηκε άδεια\nγια τον λογαριασμό %s." + "Ζητήθηκε άδεια από την εφαρμογή %1$s\nγια πρόσβαση στον λογαριασμό %2$s." "Χρησιμοποιείτε αυτήν την εφαρμογή εκτός του προφίλ εργασίας σας" "Χρησιμοποιείτε αυτήν την εφαρμογή στο προφίλ εργασίας" "Μέθοδος εισόδου" diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index c748cc80cb23..a0a64c9c1999 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -1413,6 +1413,7 @@ "Deny" "Permission requested" "Permission requested\nfor account %s." + "Permission requested by %1$s\nfor account %2$s." "You\'re using this app outside of your work profile" "You\'re using this app in your work profile" "Input Method" diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index d6faf46ee74a..3a82c601090f 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1413,6 +1413,7 @@ "Deny" "Permission requested" "Permission requested\nfor account %s." + "Permission requested by %1$s\nfor account %2$s." "You\'re using this app outside of your work profile" "You\'re using this app in your work profile" "Input Method" diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 695ddb0e4e4e..bdeee0a9809f 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -1413,6 +1413,7 @@ "Deny" "Permission requested" "Permission requested\nfor account %s." + "Permission requested by %1$s\nfor account %2$s." "You\'re using this app outside of your work profile" "You\'re using this app in your work profile" "Input Method" diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index 596d4b658769..d1302d304a72 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -1413,6 +1413,7 @@ "Deny" "Permission requested" "Permission requested\nfor account %s." + "Permission requested by %1$s\nfor account %2$s." "You\'re using this app outside of your work profile" "You\'re using this app in your work profile" "Input Method" diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 2cd891f57281..920808b9b492 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -1413,6 +1413,7 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‎Deny‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎Permission requested‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‎‎‎‏‎‎‏‎‎Permission requested‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎for account ‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎.‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‎Permission requested by ‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎for account ‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎You\'re using this app outside of your work profile‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎You\'re using this app in your work profile‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‎‏‎‎‎‎Input method‎‏‎‎‏‎" diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 5b216612430e..8ad378d3ecd8 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1413,6 +1413,7 @@ "Denegar" "Permiso solicitado" "Permiso solicitado\npara la cuenta %s" + "%1$s solicitó permiso\npara acceder a la cuenta %2$s." "Estás utilizando esta aplicación fuera del perfil de trabajo." "Estás utilizando esta aplicación en tu perfil de trabajo." "Método de entrada" diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 13f1b5613169..4f6dc6414a97 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -1413,6 +1413,7 @@ "Denegar" "Permiso solicitado" "Permiso solicitado\npara la cuenta %s" + "Permiso solicitado por %1$s\npara acceder a la cuenta%2$s." "Estás usando esta aplicación fuera del perfil de trabajo" "Estás usando esta aplicación en tu perfil de trabajo" "Método de introducción de texto" diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index ea6fabe0556f..e58422ab4fee 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -1413,6 +1413,7 @@ "Keela" "Taotletud luba" "Luba on taotletud\nkontole %s." + "Rakendus %1$s nõuab luba\nkontole %2$s juurdepääsemiseks." "Kasutate rakendust väljaspool tööprofiili" "Kasutate seda rakendust oma tööprofiilil" "Sisestusmeetod" diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 99012924a3e2..7bd4bfc56949 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1413,6 +1413,7 @@ "Ukatu" "Baimena eskatu da" "Baimena eskatu da \n%s konturako." + "%1$s aplikazioak %2$s kontua atzitzeko baimena\neskatu du." "Laneko profiletik kanpo ari zara aplikazioa erabiltzen" "Laneko profilean ari zara aplikazioa erabiltzen" "Idazketa-metodoa" diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 3dd8173ae4e1..ff775bcab8eb 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1413,6 +1413,7 @@ "مجاز نبودن" "مجوز درخواست شد" "مجوز\nبرای حساب %s درخواست شد." + "%1$s برای دسترسی به حساب %2$s\nدرخواست اجازه کرد." "شما از این برنامه در خارج از نمایه کاری‌تان استفاده می‌کنید" "از این برنامه در نمایه کاری‌تان استفاده می‌کنید" "روش ورودی" diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 527d5a6a8087..87cc6af3b34c 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1413,6 +1413,7 @@ "Kiellä" "Lupa pyydetty" "Pyydetään lupaa\ntilille %s." + "%1$s pyytänyt pääsyä\ntilille %2$s." "Käytät sovellusta muulla kuin työprofiililla" "Käytät sovellusta työprofiililla" "Syöttötapa" diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 8002080a1005..f46e648232e2 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -1413,6 +1413,7 @@ "Refuser" "Autorisation demandée" "Autorisation demandée\npour le compte \"%s\"" + "Autorisation demandée par %1$s\npour le compte %2$s." "Vous utilisez cette application en dehors de votre profil professionnel" "Vous utilisez cette application dans votre profil professionnel" "Mode de saisie" diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 7d777542e6f4..6355e621e8e9 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -1413,6 +1413,7 @@ "Refuser" "Autorisation demandée" "Autorisation demandée\npour le compte \"%s\"" + "Autorisation demandée par %1$s\npour le compte %2$s." "Vous utilisez cette application en dehors de votre profil professionnel." "Vous utilisez cette application dans votre profil professionnel." "Mode de saisie" diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 7cc6f6934901..86915dd2bb09 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1413,6 +1413,7 @@ "Rexeitar" "Permiso solicitado" "Permiso solicitado\npara a conta %s." + "%1$s solicitou permiso\npara acceder á conta %2$s." "Estás usando esta aplicación fóra do teu perfil de traballo" "Estás usando esta aplicación no teu perfil de traballo" "Método de introdución de texto" diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 758b2a014633..d1bea9bc507b 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -1413,6 +1413,7 @@ "નકારો" "પરવાનગીની વિનંતી કરી" "એકાઉન્ટ %s માટે\nપરવાનગીની વિનંતી કરી." + "%2$s એકાઉન્ટ માટે\n%1$s દ્વારા પરવાનગીની વિનંતી કરવામાં આવી." "તમે તમારી કાર્ય પ્રોફાઇલની બહાર આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો" "તમે તમારી કાર્ય પ્રોફાઇલમાં આ એપ્લિકેશનનો ઉપયોગ કરી રહ્યાં છો" "ઇનપુટ પદ્ધતિ" diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 7fdbb8a60989..481a9deb9ed1 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1413,6 +1413,7 @@ "अस्वीकारें" "अनुमति अनुरोधित" "%s खाते के लिए अनुमति\nका अनुरोध किया गया." + "%1$s ने %2$s खाते को ऐक्सेस\nकरने की अनुमति का अनुरोध किया है." "आप इस ऐप्स का उपयोग अपनी वर्क प्रोफ़ाइल से बाहर कर रहे हैं" "आप इस ऐप्स का उपयोग अपनी वर्क प्रोफ़ाइल में कर रहे हैं" "इनपुट विधि" diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 5d4905fb5680..18327375a156 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -1433,6 +1433,7 @@ "Odbij" "Zatražena je dozvola" "Zatražena je dozvola\nza račun %s." + "Aplikacija %1$s zatražila je dopuštenje\nza račun %2$s." "Ovu aplikaciju upotrebljavate izvan svog radnog profila" "Upotrebljavate tu aplikaciju u radnom profilu" "Način unosa" diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 4492eec7d8be..f9c55767e1ca 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -1413,6 +1413,7 @@ "Elutasítás" "Az engedélykérés megtörtént" "Az engedélykérés megtörtént\na(z) %s fiók számára." + "A(z) %1$s alkalmazás által kért engedély\na következő fiók számára: %2$s." "Ezt az alkalmazást munkaprofilján kívül használja" "Munkaprofiljában már használja az alkalmazást" "Beviteli mód" diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 2288e68d7b1b..986c3e7259ad 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1413,6 +1413,7 @@ "Մերժել" "Թույլտվության հարցում է արված" "Թույլտվության հարցում է արված\n%s հաշվի համար:" + "Հայցվում է թույլտվություն %1$s հավելվածի կողմից\n%2$s հաշվի համար" "Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլից դուրս" "Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլում" "Ներածման եղանակը" diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 12d479d95e8e..43238dc2c92b 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -1413,6 +1413,7 @@ "Tolak" "Izin dimintakan" "Izin dimintakan\nuntuk akun %s." + "%1$s meminta izin\nuntuk akun %2$s." "Anda menggunakan aplikasi ini di luar profil kerja" "Anda menggunakan aplikasi ini di profil kerja" "Metode masukan" diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 1ca4e619b66c..dde1424f3379 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -1413,6 +1413,7 @@ "Hafna" "Beðið um heimild" "Beðið um heimild\nfyrir reikninginn %s." + "Beiðni um heimild frá %1$s\nfyrir reikninginn %2$s." "Þú ert að nota þetta forrit utan vinnusniðsins" "Þú ert að nota þetta forrit á vinnusniðinu þínu" "Innsláttaraðferð" diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 054344ebabe5..83a7ee88d2ac 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1413,6 +1413,7 @@ "Rifiuta" "Autorizzazione richiesta" "Autorizzazione richiesta\nper l\'account %s." + "Autorizzazione richiesta da %1$s\nper l\'account %2$s." "Stai utilizzando l\'app al di fuori del tuo profilo di lavoro" "Stai utilizzando l\'app nel tuo profilo di lavoro" "Metodo inserimento" diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 757041c4d397..c2f78a4921d6 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1453,6 +1453,7 @@ "עדיף שלא" "בקשת הרשאה" "נדרשת הרשאה\nלחשבון %s." + "התבקשה הרשאה על ידי %1$s\nלחשבון %2$s." "אתה משתמש באפליקציה זו מחוץ לפרופיל העבודה שלך" "אתה משתמש באפליקציה זו בפרופיל העבודה שלך" "שיטת קלט" diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 4a8179142c5b..526d9226d6ee 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -1413,6 +1413,7 @@ "拒否" "権限がリクエストされました" "次のアカウントにアクセスする権限が\nリクエストされました: %s" + "アカウント %2$s へのアクセス権限が\n%1$s からリクエストされました。" "仕事用プロファイルの外部でこのアプリを使用しています" "仕事用プロファイルでこのアプリを使用しています" "入力方法" diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 7365b05ee513..8102f353a83d 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -1413,6 +1413,7 @@ "აკრძალვა" "მოთხოვნილია ნებართვა" "მოთხოვნილია ნებრათვა \nანგარიშისთვის: %s" + "ნებართვა მოთხოვნილია %1$s-ის მიერ\nანგარიშისთვის %2$s." "იყენებთ ამ აპს თქვენს სამუშაო პროფილს მიღმა" "ამ აპს თქვენს სამუშაო პროფილში იყენებთ" "შეყვანის მეთოდი" diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 18476482fa42..e4c354a6b7b6 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -1413,6 +1413,7 @@ "Бас тарту" "Рұқсат өтінілді" "Рұқсат \nесептік жазба үшін %s өтінілді." + "%2$s аккаунты үшін %1$s\nқолданбасы арқылы рұқсат сұралды." "Осы қолданбаны жұмыс профиліңізден тыс пайдаланып жатырсыз" "Осы қолданбаны жұмыс профиліңізде пайдаланып жатырсыз" "Енгізу әдісі" diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 95b253f25d78..692f8b0b4d3d 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -1413,6 +1413,7 @@ "បដិសេធ" "បាន​ស្នើ​សិទ្ធិ" "បាន​ស្នើ​សិទ្ធិ\nសម្រាប់​គណនី %s ។" + "ការអនុញ្ញាត​ដែលស្នើដោយ %1$s\nសម្រាប់គណនី %2$s។" "អ្នក​កំពុង​ប្រើ​កម្មវិធី​នេះ​នៅ​ខាងក្រៅ​ប្រវត្តិរូប​​ការងារ​របស់​អ្នក" "អ្នក​កំពុង​ប្រើ​កម្មវិធី​នេះ​ក្នុង​ប្រវត្តិរូប​ការងារ​របស់​អ្នក" "វិធីសាស្ត្រ​បញ្ចូល" diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 37d20495cbde..019e6777d9fe 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1413,6 +1413,7 @@ "ನಿರಾಕರಿಸಿ" "ಅನುಮತಿ ವಿನಂತಿಸಲಾಗಿದೆ" "%s ಖಾತೆಗಾಗಿ\n ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ." + "%2$s ಖಾತೆಗಾಗಿ \n %1$s ನಿಂದ ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ." "ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ನ ಹೊರಗೆ ನೀವು ಈ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಬಳಸುತ್ತಿರುವಿರಿ" "ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್‌ನಲ್ಲಿ ನೀವು ಈ ಅಪ್ಲಿಕೇಶನ್‌ ಅನ್ನು ಬಳಸುತ್ತಿರುವಿರಿ" "ಇನ್‌ಪುಟ್ ವಿಧಾನ" diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 7dcbaa00c476..6b390a0c6a78 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -1413,6 +1413,7 @@ "거부" "권한 요청됨" "%s 계정에 대해\n권한 요청" + "%1$s에서 %2$s 계정에 대한\n권한을 요청했습니다" "직장 프로필 외부에서 이 앱을 사용 중입니다." "직장 프로필에서 이 앱을 사용 중입니다." "입력 방법" diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 6420e45fe02e..1eb107152bfe 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1413,6 +1413,7 @@ "Уруксат берилбейт" "Уруксат талап кылуу" "Кийинки эсепке\nуруксат талап кылынууда: %s." + "%1$s колдонмосу\n%2$s аккаунтуна кирүүгө уруксат сурады." "Бул колдонмо жумуш профилиңиздин сыртында колдонулуп жатат" "Бул колдонмону жумуш профилиңизде пайдаланып жатасыз" "Киргизүү ыкмасы" diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 47bd5a8da60e..57acf482dd1d 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -1413,6 +1413,7 @@ "ປະ​ຕິ​ເສດ" "ຕ້ອງການການອະນຸຍາດ" "ຮ້ອງຂໍການກຳນົດສິດ\nສຳລັບບັນຊີ %s ແລ້ວ." + "ຮ້ອງຂໍການອະນຸຍາດໂດຍ %1$s\nສຳລັບບັນຊີ %2$s." "​ທ່ານ​ກຳ​ລັງ​ໃຊ້​ແອັບຯ​ນີ້ນອກ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ" "​ທ່ານ​ກຳ​ລັງ​ໃຊ້​ແອັບຯ​ນີ້​ໃນ​ໂປຣ​ໄຟລ໌​​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ" "ວິທີການປ້ອນຂໍ້ມູນ" diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 6a4958219732..cb69d1ab99d0 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -1453,6 +1453,7 @@ "Atmesti" "Pateikta užklausa dėl leidimo" "Pateikta leidimo užklausa\ndėl %s paskyros" + "Programai „%1$s“ reikalingas leidimas\n, susijęs su paskyra %2$s." "Šią programą naudojate ne darbo profilyje" "Šią programą naudojate darbo profilyje" "Įvesties būdas" diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 8e67568e1718..d5caa65e5187 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -1433,6 +1433,7 @@ "Noraidīt" "Atļauja ir pieprasīta." "Atļauja kontam %s\nir pieprasīta." + "Lietotne %1$s pieprasīja atļauju piekļūt \nkontam %2$s." "Šo lietotni izmantojat ārpus sava darba profila" "Jūs izmantojat šo lietotni no sava darba profila." "Ievades metode" diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 92d8e36fbe6b..32ba34c6a89d 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -1413,6 +1413,7 @@ "Одбиј" "Побарана е дозвола" "Побарана е дозвола\nза сметка %s." + "%1$s побара дозвола\nза сметката %2$s." "Ја користите апликацијата надвор од работниот профил" "Ја користите апликацијата во работниот профил" "Метод на внес" diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 4a62f7286e63..ab631e9a5f4f 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -1413,6 +1413,7 @@ "നിരസിക്കുക" "അനുമതി ആവശ്യമാണ്" "%s എന്ന അക്കൗണ്ടിനായി\nഅനുമതി അഭ്യർത്ഥിച്ചു." + "%2$s അക്കൗണ്ട് ആക്സസ് ചെയ്യാൻ \n%1$s അനുമതി അഭ്യർത്ഥിച്ചു." "നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിന് പുറത്ത് ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നു" "നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലിൽ ഈ അപ്ലിക്കേഷൻ ഉപയോഗിക്കുന്നു" "ടൈപ്പുചെയ്യൽ രീതി" diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index ed77e86a2ad1..768b8cd3a30f 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1413,6 +1413,7 @@ "Татгалзах" "Зөвшөөрөл хүсэв" "%s бүртгэл зөвшөөрөл \n хүссэн" + "%1$s\n нь %2$s бүртгэлд зөвшөөрөл хүссэн." "Та энэ апп-г өөрийн ажлын профайлаас гадуур ашиглаж байна" "Та энэ апп-г өөрийн ажлын профайл дотор ашиглаж байна" "Оруулах арга" diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 46057eea940e..80c490b78712 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1413,6 +1413,7 @@ "नकार द्या" "परवानगीची विनंती केली" "%s खात्यासाठी\nपरवानगीची विनंती केली." + "%1$s ने तुमचे \n%2$s खाते ॲक्सेस करण्यासाठी परवानगीची विनंती केली आहे." "तुम्ही हा अ‍ॅप आपल्‍या कार्य प्रोफाईलच्या बाहेर वापरत आहात" "तुम्ही हा अ‍ॅप आपल्या कार्य प्रोफाईलमध्‍ये वापरत आहात" "इनपुट पद्धत" diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index f8efcfd5216a..cf91addc0b9d 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -1413,6 +1413,7 @@ "Nafi" "Kebenaran diminta" "Kebenaran diminta\nuntuk akaun %s." + "Kebenaran diminta oleh %1$s\nuntuk akaun %2$s." "Anda menggunakan apl ini di luar profil kerja anda" "Anda menggunakan apl ini dalam profil kerja anda" "Kaedah input" diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index c0e3fb9a30fb..675c1837dd75 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1413,6 +1413,7 @@ "ငြင်းပယ်ရန်" "ခွင့်ပြုချက် တောင်းခံထားခြင်း" "အကောင့် %s အတွက် \n ခွင့်ပြုချက် တောင်းခံထားပြီး" + "%2$s အကောင့်အတွက်\n%1$s က ခွင့်ပြုချက် တောင်းခံထားသည်။" "သင်သည် ဒီအက်ပ်ကို သင့်အလုပ်ပရိုဖိုင် ပြင်ပတွင် အသုံးပြုနေ၏" "သင်သည် ဒီအက်ပ်ကို သင်၏ အလုပ် ပရိုဖိုင် ထဲမှာ အသုံးပြုနေသည်" "ထည့်သွင်းရန်နည်းလမ်း" diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 4a89f37af147..7b99ec98ec51 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1413,6 +1413,7 @@ "Avslå" "Tillatelse forespurt" "Tillatelse forespurt\nfor kontoen %s." + "Tillatelse forespurt av %1$s\nfor kontoen %2$s." "Du bruker denne appen utenfor arbeidsprofilen" "Du bruker denne appen i jobbprofilen din" "Inndatametode" diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 343d0b22e4d4..ba55cc3b7521 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1413,6 +1413,7 @@ "अस्वीकार गर्नुहोस्" "अनुरोध गरिएको अनुमति" \n"खाता %sको लागि अनुरोध गरिएको अनुमति।" + "%1$s ले %2$s खाता चलाउने\nअनुमति मागेको छ।" "तपाईं तपाईंको कार्य प्रोफाइल बाहिर यो एप प्रयोग गरिरहनु भएको छ" "तपाईं आफ्नो कार्य प्रोफाइलमा यो एप प्रयोग गरिरहनु भएको छ" "इनपुट विधि" diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml index 39cdce9cc46b..d5d36830a320 100644 --- a/core/res/res/values-night/colors.xml +++ b/core/res/res/values-night/colors.xml @@ -27,7 +27,7 @@ #ddffffff - @color/black + #000 @color/list_divider_color_dark @color/loading_gradient_background_color_dark diff --git a/core/res/res/values-night/corvus_colors.xml b/core/res/res/values-night/corvus_colors.xml index 26478f7cd5bf..bf567ed70d21 100644 --- a/core/res/res/values-night/corvus_colors.xml +++ b/core/res/res/values-night/corvus_colors.xml @@ -16,7 +16,19 @@ --> - @color/material_grey_800 @color/white + #212121 + + + #000000 + #212121 + + + #000000 + #212121 + + + #212121 + diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 1a8ce28e3561..0937031d99bd 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -1411,8 +1411,8 @@ "Verzoek om toegang" "Toestaan" "Weigeren" - "Rechten gevraagd" - "Rechten gevraagd\nvoor account %s." + "Toestemming gevraagd" + "Toestemming gevraagd\nvoor account %s." "Je gebruikt deze app buiten je werkprofiel" "U gebruikt deze app in je werkprofiel" "Invoermethode" diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 386d9e05124d..9af7cf3a69be 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -1413,6 +1413,7 @@ "ଅଗ୍ରାହ୍ୟ କରନ୍ତୁ" "ଅନୁମତି ଅନୁରୋଧ କରାଯାଇଛି" "%s ଆକାଉଣ୍ଟ ପାଇଁ ଅନୁମତି\n ଅନୁରୋଧ କରାଯାଇଛି।" + "%2$s ଆକାଉଣ୍ଟକୁ ଆକ୍ସେସ୍ ପାଇଁ\n%1$s ଦ୍ୱାରା ଅନୁମତି ନିମନ୍ତେ ଅନୁରୋଧ କରାଯାଇଛି।" "ଆପଣ ନିଜର ୱର୍କ ପ୍ରୋଫାଇଲ୍‌ ବାହାରେ ଏହି ଆପ୍‌ର ପ୍ରୟୋଗ କରୁଛନ୍ତି" "ଆପଣ ନିଜ ୱର୍କ ପ୍ରୋଫାଇଲ୍‌ରେ ଏହି ଆପ୍‌ର ବ୍ୟବହାର କରୁଛନ୍ତି" "ଇନପୁଟ୍ ପଦ୍ଧତି" diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 77aceb7264f4..caded7e6a008 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -1413,6 +1413,7 @@ "ਅਸਵੀਕਾਰ ਕਰੋ" "ਅਨੁਮਤੀ ਦੀ ਬੇਨਤੀ ਕੀਤੀ" "%s ਖਾਤੇ ਲਈ ਅਨੁਮਤੀ ਦੀ ਬੇਨਤੀ ਕੀਤੀ\n।" + "%1$s ਨੇ %2$s ਖਾਤੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ\nਦੀ ਇਜਾਜ਼ਤ ਲਈ ਬੇਨਤੀ ਕੀਤੀ।" "ਤੁਸੀਂ ਇਹ ਐਪ ਆਪਣੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦੇ ਬਾਹਰ ਵਰਤ ਰਹੇ ਹੋ" "ਤੁਸੀਂ ਇਹ ਐਪ ਆਪਣੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿੱਚ ਵਰਤ ਰਹੇ ਹੋ" "ਇਨਪੁੱਟ ਵਿਧੀ" diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 9b6edd21b6ac..1a84dba1e880 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -1453,8 +1453,8 @@ "Odmów" "Prośba o pozwolenie" "Prośba o pozwolenie\ndotyczące konta %s" - "Używasz tej aplikacji poza profilem służbowym" - "Używasz tej aplikacji w swoim profilu służbowym" + "Używasz tej aplikacji poza profilem do pracy" + "Używasz tej aplikacji w swoim profilu do pracy" "Sposób wprowadzania tekstu" "Synchronizacja" "Ułatwienia dostępu" diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index ec34e4e6f8c8..35ccbdb06e5a 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1413,6 +1413,7 @@ "Negar" "Permissão solicitada" "Permissão solicitada\npara a conta %s." + "Permissão solicitada pelo app %1$s\npara a conta %2$s." "Este app está sendo usado fora de seu perfil de trabalho" "Você está usando este app em seu perfil de trabalho" "Método de entrada" diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 6de3cdffefae..387d9a79db94 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1413,6 +1413,7 @@ "Recusar" "Permissão solicitada" "Permissão solicitada\npara a conta %s." + "Autorização solicitada pela app %1$s\npara a conta %2$s." "Está a utilizar esta app fora do seu perfil de trabalho" "Está a utilizar esta app no seu perfil de trabalho" "Método de entrada" diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index ec34e4e6f8c8..35ccbdb06e5a 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1413,6 +1413,7 @@ "Negar" "Permissão solicitada" "Permissão solicitada\npara a conta %s." + "Permissão solicitada pelo app %1$s\npara a conta %2$s." "Este app está sendo usado fora de seu perfil de trabalho" "Você está usando este app em seu perfil de trabalho" "Método de entrada" diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index bffa4570ef2a..b77851b76cf6 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1433,6 +1433,7 @@ "Refuzați" "Permisiune solicitată" "Permisiune solicitată\npentru contul %s." + "Permisiune solicitată de %1$s\npentru contul %2$s." "Utilizați această aplicație în afara profilului de serviciu" "Utilizați această aplicație în profilul de serviciu" "Metodă de intrare" diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 20407b131907..2fab14de573d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1453,6 +1453,7 @@ "Отклонить" "Разрешение запрошено" "Требуется разрешение\nдля аккаунта %s." + "Разрешение запрошено приложением \"%1$s\"\nдля аккаунта %2$s." "Это приложение используется в личном профиле" "Вы перешли в рабочий профиль" "Способ ввода" diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index dc8f723af411..825fdfa3af0b 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -1413,6 +1413,7 @@ "ප්‍රතික්ෂේප කරන්න" "අවසර ඉල්ලා සිටී" "%s ගිණුම සඳහා\nඅවසර ඉල්ලන ලදි." + "%2$s ගිණුම සඳහා %1$s\n විසින් ඉල්ලූ අවසරය" "මෙම යෙදුම ඔබගේ කාර්යාල පැතිකඩින් පිට දී ඔබ භාවිතා කරයි" "මෙම යෙදුම ඔබගේ පුද්ගලික කොටසේ ඔබ භාවිතා කරයි" "ආදාන ක්‍රමය" diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 624d55492603..cfc5f394150e 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -1453,6 +1453,7 @@ "Zamietnuť" "Vyžaduje sa povolenie" "Vyžaduje sa oprávnenie\npre účet %s" + "Povolenia, ktoré aplikácia %1$s požaduje\npre účet %2$s." "Túto aplikáciu používate mimo svojho pracovného profilu" "Túto aplikáciu používate vo svojom pracovnom profile" "Metóda vstupu" diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 32cfb18501d2..0c681ec9a49f 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1453,6 +1453,7 @@ "Zavrni" "Zahtevano je dovoljenje" "Zahtevano je dovoljenje\nza račun %s." + "Aplikacija %1$s je zahtevala dovoljenje\nza račun %2$s." "Aplikacijo uporabljate zunaj delovnega profila" "To aplikacijo uporabljate v delovnem profilu" "Način vnosa" diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 0c2b143bc808..6e0436ed8884 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1413,6 +1413,7 @@ "Moho" "Kërkohet leje" "Kërkohet leje\npër llogarinë %s." + "Kërkohet leja nga %1$s\npër llogarinë %2$s." "Po e përdor këtë aplikacion jashtë profilit tënd të punës" "Këtë aplikacion po e përdor në profilin tënd të punës" "Metoda e hyrjeve" diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index d2e78651ef22..d69ed48f09e5 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -1433,6 +1433,7 @@ "Одбиј" "Затражена је дозвола" "Затражена је дозвола\nза налог %s" + "%1$s тражи дозволу \nза налог %2$s." "Користите ову апликацију изван пословног профила" "Користите ову апликацију на пословном профилу" "Метод уноса" diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 66bf9c2d8030..6688fe210b9b 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -1413,6 +1413,7 @@ "Neka" "Begärd behörighet" "Begärd behörighet\nför kontot %s." + "Behörighet har begärts av %1$s\nför kontot %2$s." "Du använder den här appen i din jobbprofil" "Du använder den här appen i din jobbprofil" "Indatametod" diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 8aca7d259c30..ef35a6fe4420 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -1413,6 +1413,7 @@ "Kataza" "Idhini imeitishwa" "Idhini imeombwa\nya akaunti%s." + "%1$s imeombwa ruhusa\nkwenye akaunti ya %2$s." "Unatumia programu hii nje ya wasifu wako wa kazini" "Unatumia programu hii kwenye wasifu wako wa kazini" "Mbinu ya uingizaji" diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 2eb628c7afb0..d6410beb93cd 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -1413,6 +1413,7 @@ "நிராகரி" "அனுமதிக் கோரப்பட்டது" "%s கணக்கிற்கான அனுமதி\nகோரப்பட்டது." + "%1$s ஆப்ஸ்\n%2$s கணக்கிற்கான அனுமதியைக் கோருகிறது." "இந்தப் பயன்பாட்டைப் பணிக் கணக்கிற்கு வெளியே பயன்படுத்துகிறீர்கள்" "பணிக் கணக்கில் பயன்பாட்டைப் பயன்படுத்துகிறீர்கள்" "உள்ளீட்டு முறை" diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index f379214734c9..988169835979 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -1413,8 +1413,8 @@ "తిరస్కరించండి" "అనుమతి అభ్యర్థించబడింది" "ఖాతా %s కోసం\nఅనుమతి అభ్యర్థించబడింది." - "మీరు మీ కార్యాలయ ప్రొఫైల్‌కు వెలుపల ఈ యాప్‌ను ఉపయోగిస్తున్నారు" - "మీరు మీ కార్యాలయ ప్రొఫైల్‌లో ఈ యాప్‌ను ఉపయోగిస్తున్నారు" + "మీరు మీ కార్యాలయ ప్రొఫైల్‌కు వెలుపల ఈ అనువర్తనాన్ని ఉపయోగిస్తున్నారు" + "మీరు మీ కార్యాలయ ప్రొఫైల్‌లో ఈ అనువర్తనాన్ని ఉపయోగిస్తున్నారు" "ఇన్‌పుట్ పద్ధతి" "సమకాలీకరణ" "యాక్సెస్ సామర్థ్యం" diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 4c6be820d4ff..08718ffd614f 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1413,6 +1413,7 @@ "ปฏิเสธ" "การอนุญาตที่ขอ" "การอนุญาตที่ขอ\nสำหรับบัญชี %s" + "สิทธิ์ที่ %1$s ขอ\nสำหรับบัญชี %2$s" "คุณกำลังใช้แอปนี้นอกโปรไฟล์งานของคุณ" "คุณกำลังใช้แอปนี้ในโปรไฟล์งานของคุณ" "วิธีป้อนข้อมูล" diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 0bd750f1aa33..0a7aa0e7ab14 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -1413,6 +1413,7 @@ "Tanggihan" "Hiniling ang pahintulot" "Hiniling ang pahintulot\npara sa account na %s." + "Humiling ang %1$s ng pahintulot\npara sa account na %2$s." "Ginagamit mo ang app na ito sa labas ng iyong profile sa trabaho" "Ginagamit mo ang app na ito sa iyong profile sa trabaho" "Pamamaraan ng pag-input" diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 87d97599a9bb..a44882498142 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -1413,6 +1413,7 @@ "Reddet" "İzin istendi" "%s hesabı için\nizin isteğinde bulunuldu." + "%1$s uygulaması, %2$s hesabı\niçin izin istedi" "Bu uygulamayı iş profilinizin dışında kullanıyorsunuz" "Bu uygulamayı iş profilinizde kullanıyorsunuz" "Giriş yöntemi" diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 067045aa0860..4605db387a44 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1453,6 +1453,7 @@ "Забор." "Потрібен дозвіл" "Запитано дозвіл\nдля облікового запису %s." + "Додаток %1$s запитує дозвіл\nна доступ до облікового запису %2$s." "Ви використовуєте цей додаток за межами робочого профілю" "Ви використовуєте цей додаток у своєму робочому профілі" "Метод введення" diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 04800531784e..06dc0751e76e 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1413,6 +1413,7 @@ "مسترد کریں" "اجازت طلب کی گئی" "اکاؤنٹ %s کیلئے\nاجازت طلب کی گئی۔" + "%2$s اکاؤنٹ کیلئے\n%1$s نے اجازت کی درخواست کی۔" "آپ اس ایپ کا استعمال اپنے دفتری پروفائل کے باہر کر رہے ہیں" "آپ اس ایپ کو اپنے دفتری پروفائل میں استعمال کر رہے ہیں" "اندراج کا طریقہ" diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index e3ed7829f1ec..f09aaa67c43a 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1413,6 +1413,7 @@ "Rad etish" "Ruxsat so‘raldi" "%s hisobi uchun\nruxsat so‘raldi" + "Ruxsat %1$s ilovasi tomonidan \n%2$s hisobi uchun soʻralgan." "Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz" "Siz ushbu ilovadan ishchi profilingizda foydalanmoqdasiz" "Kiritish uslubi" diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 8e0cc2ead613..d19ecf567c54 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1413,6 +1413,7 @@ "Từ chối" "Đã yêu cầu quyền" "Đã yêu cầu quyền\ncho tài khoản %s." + "Quyền do %1$s\nyêu cầu cho tài khoản %2$s." "Bạn đang sử dụng ứng dụng này bên ngoài hồ sơ công việc của mình" "Bạn đang sử dụng ứng dụng này trong hồ sơ công việc của mình" "Phương thức nhập" diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index a645cd7db90a..74dde0ec4550 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -1413,6 +1413,7 @@ "拒绝" "权限请求" "应用对帐号 %s\n 提出权限请求。" + "“%1$s”请求获得以下帐号的访问权限:\n%2$s。" "您目前是在工作资料之外使用此应用" "您目前是在工作资料内使用此应用" "输入法" diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 9eef703670ef..6cae6439ffd3 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1413,6 +1413,7 @@ "拒絕" "已要求權限" "%s 帳戶的\n權限要求。" + "「%1$s」要求帳戶 %2$s\n的權限" "您目前並未透過公司檔案使用這個應用程式" "您目前透過公司檔案使用這個應用程式" "輸入法" diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index c4f5dc8d3661..58af46e65f60 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -1413,6 +1413,7 @@ "拒絕" "已要求權限" "帳戶 %s 已提出\n權限要求。" + "「%1$s」要求授予\n%2$s 帳戶的權限。" "你目前並非透過工作資料夾使用這個應用程式" "你目前透過工作設定檔使用這個應用程式" "輸入法" diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index bb5360edb0b8..c84b44720467 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -1413,6 +1413,7 @@ "Yala" "Imvume Iceliwe" "Imvume Iceliwe \n ye-akhawunti %s" + "Imvume ecelwe yi-%1$s\nye-akhawunti ye-%2$s." "Usebenzisa lolu hlelo lokusebenza ngaphandle kwephrofayela yakho yomsebenzi" "Usebenzisa lolu hlelo lokusebenza kuphrofayela yakho yomsebenzi" "Indlela yokufakwayo" diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml index fc9e060cd3f4..5e8dcd306023 100644 --- a/core/res/res/values/colors_device_defaults.xml +++ b/core/res/res/values/colors_device_defaults.xml @@ -17,19 +17,19 @@ - #ff2d2d2d - @color/primary_material_light - #ff2d2d2d - #ffffffff - #ff242424 - @color/primary_dark_material_light - #ff000000 - #ffffffff + @color/monet_background_secondary_device_default + @color/monet_background_secondary_device_default + @color/monet_background_device_default + @color/monet_background_device_default + @color/monet_background_device_default + @color/monet_background_device_default + @color/monet_background_device_default + @color/monet_background_device_default #1f000000 - #ff3a3a3a - @color/secondary_material_settings_light + @color/monet_background_secondary_device_default + @color/monet_background_secondary_device_default #ff616161 #ff9e9e9e @@ -37,10 +37,11 @@ #0086FA @color/accent_device_default_light - @color/background_material_dark - #ffffffff - #ff3c4043 - @color/background_floating_material_light + + @color/monet_background_device_default + @color/monet_background_device_default + @color/monet_background_secondary_device_default + @color/monet_background_secondary_device_default #fff28b82 diff --git a/core/res/res/values/corvus_colors.xml b/core/res/res/values/corvus_colors.xml index 9aa42bc37afc..c567c6805078 100644 --- a/core/res/res/values/corvus_colors.xml +++ b/core/res/res/values/corvus_colors.xml @@ -16,7 +16,25 @@ --> - @color/white + + #fff + #fff + + + #fff + #fff + #fff + #fff + + + #fff + #fff + #fff + + + #fff + + @color/monet_background_device_default @color/black diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e00aff1af37b..94a8c9a8d198 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3043,7 +3043,7 @@ =============================================================== --> - + @@ -3051,7 +3051,26 @@ - + + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 18f95063035d..cefd69e7d31f 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -166,6 +166,8 @@ easier.