diff options
217 files changed, 6444 insertions, 2100 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java index 4dc9cf850893..cc3e9c33fe42 100644 --- a/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java +++ b/apex/jobscheduler/service/java/com/android/server/AppStateTrackerImpl.java @@ -274,11 +274,8 @@ public class AppStateTrackerImpl implements AppStateTracker { int uid, @NonNull String packageName) { updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid)); - if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ false)) { + if (!sender.areAlarmsRestricted(uid, packageName)) { unblockAlarmsForUidPackage(uid, packageName); - } else if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/ true)) { - // we need to deliver the allow-while-idle alarms for this uid, package - unblockAllUnrestrictedAlarms(); } if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) { @@ -302,6 +299,7 @@ public class AppStateTrackerImpl implements AppStateTracker { final boolean isActive = sender.isUidActive(uid); updateJobsForUid(uid, isActive); + updateAlarmsForUid(uid); if (isActive) { unblockAlarmsForUid(uid); @@ -313,7 +311,7 @@ public class AppStateTrackerImpl implements AppStateTracker { */ private void onPowerSaveUnexempted(AppStateTrackerImpl sender) { updateAllJobs(); - unblockAllUnrestrictedAlarms(); + updateAllAlarms(); } /** @@ -322,6 +320,8 @@ public class AppStateTrackerImpl implements AppStateTracker { */ private void onPowerSaveExemptionListChanged(AppStateTrackerImpl sender) { updateAllJobs(); + updateAllAlarms(); + unblockAllUnrestrictedAlarms(); } /** @@ -344,7 +344,7 @@ public class AppStateTrackerImpl implements AppStateTracker { private void onExemptedBucketChanged(AppStateTrackerImpl sender) { // This doesn't happen very often, so just re-evaluate all jobs / alarms. updateAllJobs(); - unblockAllUnrestrictedAlarms(); + updateAllAlarms(); } /** @@ -352,10 +352,7 @@ public class AppStateTrackerImpl implements AppStateTracker { */ private void onForceAllAppsStandbyChanged(AppStateTrackerImpl sender) { updateAllJobs(); - - if (!sender.isForceAllAppsStandbyEnabled()) { - unblockAllUnrestrictedAlarms(); - } + updateAllAlarms(); } /** @@ -387,6 +384,19 @@ public class AppStateTrackerImpl implements AppStateTracker { } /** + * Called when all alarms need to be re-evaluated for eligibility based on + * {@link #areAlarmsRestrictedByBatterySaver}. + */ + public void updateAllAlarms() { + } + + /** + * Called when the given uid state changes to active / idle. + */ + public void updateAlarmsForUid(int uid) { + } + + /** * Called when the job restrictions for multiple UIDs might have changed, so the alarm * manager should re-evaluate all restrictions for all blocked jobs. */ @@ -918,7 +928,7 @@ public class AppStateTrackerImpl implements AppStateTracker { // Feature flag for forced app standby changed. final boolean unblockAlarms; synchronized (mLock) { - unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby; + unblockAlarms = !mForcedAppStandbyEnabled; } for (Listener l : cloneListeners()) { l.updateAllJobs(); @@ -1109,53 +1119,64 @@ public class AppStateTrackerImpl implements AppStateTracker { } /** - * @return whether alarms should be restricted for a UID package-name. - */ - public boolean areAlarmsRestricted(int uid, @NonNull String packageName, - boolean isExemptOnBatterySaver) { - return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ false, - isExemptOnBatterySaver); - } - - /** - * @return whether jobs should be restricted for a UID package-name. + * @return whether alarms should be restricted for a UID package-name, due to explicit + * user-forced app standby. Use {{@link #areAlarmsRestrictedByBatterySaver} to check for + * restrictions induced by battery saver. */ - public boolean areJobsRestricted(int uid, @NonNull String packageName, - boolean hasForegroundExemption) { - return isRestricted(uid, packageName, /*useTempExemptionListToo=*/ true, - hasForegroundExemption); + public boolean areAlarmsRestricted(int uid, @NonNull String packageName) { + if (isUidActive(uid)) { + return false; + } + synchronized (mLock) { + final int appId = UserHandle.getAppId(uid); + if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) { + return false; + } + return (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)); + } } /** - * @return whether foreground services should be suppressed in the background - * due to forced app standby for the given app + * @return whether alarms should be restricted when due to battery saver. */ - public boolean areForegroundServicesRestricted(int uid, @NonNull String packageName) { + public boolean areAlarmsRestrictedByBatterySaver(int uid, @NonNull String packageName) { + if (isUidActive(uid)) { + return false; + } synchronized (mLock) { - return isRunAnyRestrictedLocked(uid, packageName); + final int appId = UserHandle.getAppId(uid); + if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) { + return false; + } + final int userId = UserHandle.getUserId(uid); + if (mAppStandbyInternal.isAppIdleEnabled() && !mAppStandbyInternal.isInParole() + && mExemptedBucketPackages.contains(userId, packageName)) { + return false; + } + return mForceAllAppsStandby; } } + /** - * @return whether force-app-standby is effective for a UID package-name. + * @return whether jobs should be restricted for a UID package-name. This could be due to + * battery saver or user-forced app standby */ - private boolean isRestricted(int uid, @NonNull String packageName, - boolean useTempExemptionListToo, boolean exemptOnBatterySaver) { + public boolean areJobsRestricted(int uid, @NonNull String packageName, + boolean hasForegroundExemption) { if (isUidActive(uid)) { return false; } synchronized (mLock) { final int appId = UserHandle.getAppId(uid); - if (ArrayUtils.contains(mPowerExemptAllAppIds, appId)) { - return false; - } - if (useTempExemptionListToo && ArrayUtils.contains(mTempExemptAppIds, appId)) { + if (ArrayUtils.contains(mPowerExemptAllAppIds, appId) + || ArrayUtils.contains(mTempExemptAppIds, appId)) { return false; } if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) { return true; } - if (exemptOnBatterySaver) { + if (hasForegroundExemption) { return false; } final int userId = UserHandle.getUserId(uid); diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java index a8c0f0ec3e00..657c368d0aee 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java @@ -42,7 +42,7 @@ import java.util.Date; */ class Alarm { @VisibleForTesting - public static final int NUM_POLICIES = 3; + public static final int NUM_POLICIES = 4; /** * Index used to store the time the alarm was requested to expire. To be used with * {@link #setPolicyElapsed(int, long)}. @@ -59,6 +59,12 @@ class Alarm { */ public static final int DEVICE_IDLE_POLICY_INDEX = 2; + /** + * Index used to store the earliest time the alarm can expire based on battery saver policy. + * To be used with {@link #setPolicyElapsed(int, long)}. + */ + public static final int BATTERY_SAVER_POLICY_INDEX = 3; + public final int type; /** * The original trigger time supplied by the caller. This can be in the elapsed or rtc time base @@ -223,6 +229,8 @@ class Alarm { return "app_standby"; case DEVICE_IDLE_POLICY_INDEX: return "device_idle"; + case BATTERY_SAVER_POLICY_INDEX: + return "battery_saver"; default: return "--unknown--"; } diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 7842d487dfb2..aa46cfdc5c8a 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -28,6 +28,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX; +import static com.android.server.alarm.Alarm.BATTERY_SAVER_POLICY_INDEX; import static com.android.server.alarm.Alarm.DEVICE_IDLE_POLICY_INDEX; import static com.android.server.alarm.Alarm.REQUESTER_POLICY_INDEX; @@ -156,6 +157,7 @@ public class AlarmManagerService extends SystemService { static final int TICK_HISTORY_DEPTH = 10; static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000; + static final long INDEFINITE_DELAY = 365 * MILLIS_IN_DAY; // Indices into the KEYS_APP_STANDBY_QUOTAS array. static final int ACTIVE_INDEX = 0; @@ -964,8 +966,7 @@ public class AlarmManagerService extends SystemService { * Check all alarms in {@link #mPendingBackgroundAlarms} and send the ones that are not * restricted. * - * This is only called when the global "force all apps-standby" flag changes or when the - * power save whitelist changes, so it's okay to be slow. + * This is only called when the power save whitelist changes, so it's okay to be slow. */ void sendAllUnrestrictedPendingBackgroundAlarmsLocked() { final ArrayList<Alarm> alarmsToDeliver = new ArrayList<>(); @@ -984,7 +985,6 @@ public class AlarmManagerService extends SystemService { Predicate<Alarm> isBackgroundRestricted) { for (int uidIndex = pendingAlarms.size() - 1; uidIndex >= 0; uidIndex--) { - final int uid = pendingAlarms.keyAt(uidIndex); final ArrayList<Alarm> alarmsForUid = pendingAlarms.valueAt(uidIndex); for (int alarmIndex = alarmsForUid.size() - 1; alarmIndex >= 0; alarmIndex--) { @@ -1620,6 +1620,44 @@ public class AlarmManagerService extends SystemService { } /** + * Adjusts the delivery time of the alarm based on battery saver rules. + * + * @param alarm The alarm to adjust + * @return {@code true} if the alarm delivery time was updated. + */ + private boolean adjustDeliveryTimeBasedOnBatterySaver(Alarm alarm) { + final long nowElapsed = mInjector.getElapsedRealtime(); + if (isExemptFromBatterySaver(alarm)) { + return false; + } + + if (!(mAppStateTracker != null && mAppStateTracker.areAlarmsRestrictedByBatterySaver( + alarm.creatorUid, alarm.sourcePackage))) { + return alarm.setPolicyElapsed(BATTERY_SAVER_POLICY_INDEX, nowElapsed); + } + + final long batterSaverPolicyElapsed; + if ((alarm.flags & (AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED)) != 0) { + // Unrestricted. + batterSaverPolicyElapsed = nowElapsed; + } else if ((alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) { + // Allowed but limited. + final long minDelay; + if (mUseAllowWhileIdleShortTime.get(alarm.creatorUid)) { + minDelay = mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; + } else { + minDelay = mConstants.ALLOW_WHILE_IDLE_LONG_TIME; + } + final long lastDispatch = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, 0); + batterSaverPolicyElapsed = (lastDispatch == 0) ? nowElapsed : lastDispatch + minDelay; + } else { + // Not allowed. + batterSaverPolicyElapsed = nowElapsed + INDEFINITE_DELAY; + } + return alarm.setPolicyElapsed(BATTERY_SAVER_POLICY_INDEX, batterSaverPolicyElapsed); + } + + /** * Adjusts the delivery time of the alarm based on device_idle (doze) rules. * * @param alarm The alarm to adjust @@ -1756,6 +1794,7 @@ public class AlarmManagerService extends SystemService { if (a.alarmClock != null) { mNextAlarmClockMayChange = true; } + adjustDeliveryTimeBasedOnBatterySaver(a); adjustDeliveryTimeBasedOnBucketLocked(a); mAlarmStore.add(a); rescheduleKernelAlarmsLocked(); @@ -2230,14 +2269,6 @@ public class AlarmManagerService extends SystemService { pw.print(": "); final long lastTime = mLastAllowWhileIdleDispatch.valueAt(i); TimeUtils.formatDuration(lastTime, nowELAPSED, pw); - - final long minInterval = getWhileIdleMinIntervalLocked(uid); - pw.print(" Next allowed:"); - TimeUtils.formatDuration(lastTime + minInterval, nowELAPSED, pw); - pw.print(" ("); - TimeUtils.formatDuration(minInterval, 0, pw); - pw.print(")"); - pw.println(); } pw.decreaseIndent(); @@ -2511,8 +2542,6 @@ public class AlarmManagerService extends SystemService { proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.UID, uid); proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.TIME_MS, lastTime); - proto.write(AlarmManagerServiceDumpProto.LastAllowWhileIdleDispatch.NEXT_ALLOWED_MS, - lastTime + getWhileIdleMinIntervalLocked(uid)); proto.end(token); } @@ -3119,30 +3148,36 @@ public class AlarmManagerService extends SystemService { } } + private boolean isExemptFromBatterySaver(Alarm alarm) { + if (alarm.alarmClock != null) { + return true; + } + if ((alarm.operation != null) + && (alarm.operation.isActivity() || alarm.operation.isForegroundService())) { + return true; + } + if (UserHandle.isCore(alarm.creatorUid)) { + return true; + } + return false; + } + private boolean isBackgroundRestricted(Alarm alarm) { - boolean exemptOnBatterySaver = (alarm.flags & FLAG_ALLOW_WHILE_IDLE) != 0; if (alarm.alarmClock != null) { // Don't defer alarm clocks return false; } - if (alarm.operation != null) { - if (alarm.operation.isActivity()) { - // Don't defer starting actual UI - return false; - } - if (alarm.operation.isForegroundService()) { - // FG service alarms are nearly as important; consult AST policy - exemptOnBatterySaver = true; - } + if (alarm.operation != null && alarm.operation.isActivity()) { + // Don't defer starting actual UI + return false; } final String sourcePackage = alarm.sourcePackage; final int sourceUid = alarm.creatorUid; if (UserHandle.isCore(sourceUid)) { return false; } - return (mAppStateTracker != null) && - mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, - exemptOnBatterySaver); + return (mAppStateTracker != null) && mAppStateTracker.areAlarmsRestricted(sourceUid, + sourcePackage); } private static native long init(); @@ -3153,46 +3188,10 @@ public class AlarmManagerService extends SystemService { private static native int setKernelTimezone(long nativeData, int minuteswest); private static native long getNextAlarm(long nativeData, int type); - private long getWhileIdleMinIntervalLocked(int uid) { - final boolean ebs = (mAppStateTracker != null) - && mAppStateTracker.isForceAllAppsStandbyEnabled(); - - if (!ebs || mUseAllowWhileIdleShortTime.get(uid)) { - // if the last allow-while-idle went off while uid was fg, or the uid - // recently came into fg, don't block the alarm for long. - return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME; - } - return mConstants.ALLOW_WHILE_IDLE_LONG_TIME; - } - boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) { boolean hasWakeup = false; final ArrayList<Alarm> pendingAlarms = mAlarmStore.removePendingAlarms(nowELAPSED); for (final Alarm alarm : pendingAlarms) { - if ((alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) { - // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can - // schedule such alarms. The first such alarm from an app is always delivered. - final long lastTime = mLastAllowWhileIdleDispatch.get(alarm.creatorUid, -1); - final long minTime = lastTime + getWhileIdleMinIntervalLocked(alarm.creatorUid); - if (lastTime >= 0 && nowELAPSED < minTime) { - // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE - // alarm went off for this app. Reschedule the alarm to be in the - // correct time period. - alarm.setPolicyElapsed(REQUESTER_POLICY_INDEX, minTime); - if (RECORD_DEVICE_IDLE_ALARMS) { - IdleDispatchEntry ent = new IdleDispatchEntry(); - ent.uid = alarm.uid; - ent.pkg = alarm.operation.getCreatorPackage(); - ent.tag = alarm.operation.getTag(""); - ent.op = "RESCHEDULE"; - ent.elapsedRealtime = nowELAPSED; - ent.argRealtime = lastTime; - mAllowWhileIdleDispatches.add(ent); - } - setImplLocked(alarm); - continue; - } - } if (isBackgroundRestricted(alarm)) { // Alarms with FLAG_WAKE_FROM_IDLE or mPendingIdleUntil alarm are not deferred if (DEBUG_BG_LIMIT) { @@ -3924,8 +3923,41 @@ public class AlarmManagerService extends SystemService { } private final Listener mForceAppStandbyListener = new Listener() { + + @Override + public void updateAllAlarms() { + // Called when: + // 1. Power exemption list changes, + // 2. Battery saver state is toggled, + // 3. Any package is moved into or out of the EXEMPTED bucket. + synchronized (mLock) { + if (mAlarmStore.updateAlarmDeliveries( + a -> adjustDeliveryTimeBasedOnBatterySaver(a))) { + rescheduleKernelAlarmsLocked(); + } + } + } + + @Override + public void updateAlarmsForUid(int uid) { + // Called when the given uid's state switches b/w active and idle. + synchronized (mLock) { + if (mAlarmStore.updateAlarmDeliveries(a -> { + if (a.creatorUid != uid) { + return false; + } + return adjustDeliveryTimeBasedOnBatterySaver(a); + })) { + rescheduleKernelAlarmsLocked(); + } + } + } + @Override public void unblockAllUnrestrictedAlarms() { + // Called when: + // 1. Power exemption list changes, + // 2. User FAS feature is disabled. synchronized (mLock) { sendAllUnrestrictedPendingBackgroundAlarmsLocked(); } @@ -3934,12 +3966,14 @@ public class AlarmManagerService extends SystemService { @Override public void unblockAlarmsForUid(int uid) { synchronized (mLock) { + // Called when the given uid becomes active. sendPendingBackgroundAlarmsLocked(uid, null); } } @Override public void unblockAlarmsForUidPackage(int uid, String packageName) { + // Called when user turns off FAS for this (uid, package). synchronized (mLock) { sendPendingBackgroundAlarmsLocked(uid, packageName); } @@ -3950,9 +3984,14 @@ public class AlarmManagerService extends SystemService { synchronized (mLock) { if (foreground) { mUseAllowWhileIdleShortTime.put(uid, true); - - // Note we don't have to drain the pending while-idle alarms here, because - // this event should coincide with unblockAlarmsForUid(). + if (mAlarmStore.updateAlarmDeliveries(a -> { + if (a.creatorUid != uid || (a.flags & FLAG_ALLOW_WHILE_IDLE) == 0) { + return false; + } + return adjustDeliveryTimeBasedOnBatterySaver(a); + })) { + rescheduleKernelAlarmsLocked(); + } } } } @@ -4236,18 +4275,20 @@ public class AlarmManagerService extends SystemService { if (allowWhileIdle) { // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm. mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED); - mAlarmStore.updateAlarmDeliveries(a -> { - if (a.creatorUid != alarm.creatorUid) { - return false; - } - return adjustDeliveryTimeBasedOnDeviceIdle(a); - }); if ((mAppStateTracker == null) || mAppStateTracker.isUidInForeground(alarm.creatorUid)) { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true); } else { mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false); } + mAlarmStore.updateAlarmDeliveries(a -> { + if (a.creatorUid != alarm.creatorUid + || (a.flags & FLAG_ALLOW_WHILE_IDLE) == 0) { + return false; + } + return adjustDeliveryTimeBasedOnDeviceIdle(a) + | adjustDeliveryTimeBasedOnBatterySaver(a); + }); if (RECORD_DEVICE_IDLE_ALARMS) { IdleDispatchEntry ent = new IdleDispatchEntry(); ent.uid = alarm.uid; diff --git a/core/api/current.txt b/core/api/current.txt index 32134fcf2026..b6a15343deda 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -6925,6 +6925,7 @@ package android.app.admin { method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String); method public CharSequence getDeviceOwnerLockScreenInfo(); method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName); + method @NonNull public String getEnrollmentSpecificId(); method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName); method @Nullable public String getGlobalPrivateDnsHost(@NonNull android.content.ComponentName); method public int getGlobalPrivateDnsMode(@NonNull android.content.ComponentName); @@ -7075,6 +7076,7 @@ package android.app.admin { method @NonNull public java.util.List<java.lang.String> setMeteredDataDisabledPackages(@NonNull android.content.ComponentName, @NonNull java.util.List<java.lang.String>); method public void setNetworkLoggingEnabled(@Nullable android.content.ComponentName, boolean); method @Deprecated public void setOrganizationColor(@NonNull android.content.ComponentName, int); + method public void setOrganizationId(@NonNull String); method public void setOrganizationName(@NonNull android.content.ComponentName, @Nullable CharSequence); method public void setOverrideApnsEnabled(@NonNull android.content.ComponentName, boolean); method @NonNull public String[] setPackagesSuspended(@NonNull android.content.ComponentName, @NonNull String[], boolean); @@ -12375,6 +12377,7 @@ package android.content.pm { field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand"; + field public static final String FEATURE_TRANSLATION = "android.software.translation"; field public static final String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory"; field public static final String FEATURE_USB_HOST = "android.hardware.usb.host"; field public static final String FEATURE_VERIFIED_BOOT = "android.software.verified_boot"; @@ -31432,6 +31435,7 @@ package android.os { method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int); method @NonNull public android.os.VibrationEffect compose(); field public static final int PRIMITIVE_CLICK = 1; // 0x1 + field public static final int PRIMITIVE_LOW_TICK = 8; // 0x8 field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6 field public static final int PRIMITIVE_QUICK_RISE = 4; // 0x4 field public static final int PRIMITIVE_SLOW_RISE = 5; // 0x5 @@ -51608,6 +51612,66 @@ package android.view.textservice { } +package android.view.translation { + + public final class TranslationManager { + method @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec); + method @NonNull @WorkerThread public java.util.List<java.lang.String> getSupportedLocales(); + } + + public final class TranslationRequest implements android.os.Parcelable { + ctor public TranslationRequest(@Nullable CharSequence); + method public int describeContents(); + method @Nullable public android.view.autofill.AutofillId getAutofillId(); + method @Nullable public CharSequence getTranslationText(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationRequest> CREATOR; + } + + public static final class TranslationRequest.Builder { + ctor public TranslationRequest.Builder(); + method @NonNull public android.view.translation.TranslationRequest build(); + method @NonNull public android.view.translation.TranslationRequest.Builder setAutofillId(@NonNull android.view.autofill.AutofillId); + method @NonNull public android.view.translation.TranslationRequest.Builder setTranslationText(@NonNull CharSequence); + } + + public final class TranslationResponse implements android.os.Parcelable { + method public int describeContents(); + method public int getTranslationStatus(); + method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslations(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationResponse> CREATOR; + field public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2; // 0x2 + field public static final int TRANSLATION_STATUS_SUCCESS = 0; // 0x0 + field public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1; // 0x1 + } + + public static final class TranslationResponse.Builder { + ctor public TranslationResponse.Builder(int); + method @NonNull public android.view.translation.TranslationResponse.Builder addTranslations(@NonNull android.view.translation.TranslationRequest); + method @NonNull public android.view.translation.TranslationResponse build(); + method @NonNull public android.view.translation.TranslationResponse.Builder setTranslationStatus(int); + method @NonNull public android.view.translation.TranslationResponse.Builder setTranslations(@NonNull java.util.List<android.view.translation.TranslationRequest>); + } + + public final class TranslationSpec implements android.os.Parcelable { + ctor public TranslationSpec(@NonNull String, int); + method public int describeContents(); + method public int getDataFormat(); + method @NonNull public String getLanguage(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.TranslationSpec> CREATOR; + field public static final int DATA_FORMAT_TEXT = 1; // 0x1 + } + + public class Translator { + method public void destroy(); + method public boolean isDestroyed(); + method @Nullable @WorkerThread public android.view.translation.TranslationResponse translate(@NonNull android.view.translation.TranslationRequest); + } + +} + package android.webkit { public abstract class ClientCertRequest { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 473a2808cd00..da79b67c245e 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -52,6 +52,7 @@ package android { field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE"; field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE"; field public static final String BIND_TIME_ZONE_PROVIDER_SERVICE = "android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"; + field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE"; field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; field public static final String BRICK = "android.permission.BRICK"; @@ -1941,6 +1942,7 @@ package android.content { field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final String TETHERING_SERVICE = "tethering"; + field public static final String TRANSLATION_MANAGER_SERVICE = "transformer"; field public static final String VR_SERVICE = "vrmanager"; field public static final String WIFI_NL80211_SERVICE = "wifinl80211"; field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager"; @@ -9854,6 +9856,48 @@ package android.service.timezone { } +package android.service.translation { + + public final class TranslationRequest implements android.os.Parcelable { + ctor public TranslationRequest(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>); + method public int describeContents(); + method @NonNull public android.view.translation.TranslationSpec getDestSpec(); + method public int getRequestId(); + method @NonNull public android.view.translation.TranslationSpec getSourceSpec(); + method @NonNull public java.util.List<android.view.translation.TranslationRequest> getTranslationRequests(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.translation.TranslationRequest> CREATOR; + } + + public static final class TranslationRequest.Builder { + ctor public TranslationRequest.Builder(int, @NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.translation.TranslationRequest>); + method @NonNull public android.service.translation.TranslationRequest.Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest); + method @NonNull public android.service.translation.TranslationRequest build(); + method @NonNull public android.service.translation.TranslationRequest.Builder setDestSpec(@NonNull android.view.translation.TranslationSpec); + method @NonNull public android.service.translation.TranslationRequest.Builder setRequestId(int); + method @NonNull public android.service.translation.TranslationRequest.Builder setSourceSpec(@NonNull android.view.translation.TranslationSpec); + method @NonNull public android.service.translation.TranslationRequest.Builder setTranslationRequests(@NonNull java.util.List<android.view.translation.TranslationRequest>); + } + + public abstract class TranslationService extends android.app.Service { + ctor public TranslationService(); + method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public void onConnected(); + method public abstract void onCreateTranslationSession(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, int); + method public void onDisconnected(); + method public abstract void onFinishTranslationSession(int); + method public abstract void onTranslationRequest(@NonNull android.service.translation.TranslationRequest, int, @NonNull android.os.CancellationSignal, @NonNull android.service.translation.TranslationService.OnTranslationResultCallback); + field public static final String SERVICE_INTERFACE = "android.service.translation.TranslationService"; + field public static final String SERVICE_META_DATA = "android.translation_service"; + } + + public static interface TranslationService.OnTranslationResultCallback { + method public void onError(); + method public void onTranslationSuccess(@NonNull android.view.translation.TranslationResponse); + } + +} + package android.service.trust { public class TrustAgentService extends android.app.Service { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7bdcbc13d163..97879b80ea06 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -39,7 +39,6 @@ import android.annotation.WorkerThread; import android.app.Activity; import android.app.IServiceConnection; import android.app.KeyguardManager; -import android.app.admin.DevicePolicyManager.DevicePolicyOperation; import android.app.admin.SecurityLog.SecurityEvent; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; @@ -12814,4 +12813,66 @@ public class DevicePolicyManager { } } } + + /** + * Returns an enrollment-specific identifier of this device, which is guaranteed to be the same + * value for the same device, enrolled into the same organization by the same managing app. + * This identifier is high-entropy, useful for uniquely identifying individual devices within + * the same organisation. + * It is available both in a work profile and on a fully-managed device. + * The identifier would be consistent even if the work profile is removed and enrolled again + * (to the same organization), or the device is factory reset and re-enrolled. + + * Can only be called by the Profile Owner or Device Owner, if the + * {@link #setOrganizationId(String)} was previously called. + * If {@link #setOrganizationId(String)} was not called, then the returned value will be an + * empty string. + * + * @return A stable, enrollment-specific identifier. + * @throws SecurityException if the caller is not a profile owner or device owner. + */ + @NonNull public String getEnrollmentSpecificId() { + if (mService == null) { + return ""; + } + + try { + return mService.getEnrollmentSpecificId(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Sets the Enterprise ID for the work profile or managed device. This is a requirement for + * generating an enrollment-specific ID for the device, see {@link #getEnrollmentSpecificId()}. + * + * It is recommended that the Enterprise ID is at least 6 characters long, and no more than + * 64 characters. + * + * @param enterpriseId An identifier of the organization this work profile or device is + * enrolled into. + */ + public void setOrganizationId(@NonNull String enterpriseId) { + setOrganizationIdForUser(mContext.getPackageName(), enterpriseId, myUserId()); + } + + /** + * Sets the Enterprise ID for the work profile or managed device. This is a requirement for + * generating an enrollment-specific ID for the device, see + * {@link #getEnrollmentSpecificId()}. + * + * @hide + */ + public void setOrganizationIdForUser(@NonNull String packageName, + @NonNull String enterpriseId, @UserIdInt int userId) { + if (mService == null) { + return; + } + try { + mService.setOrganizationIdForUser(packageName, enterpriseId, userId); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 4b87bb9cae6c..e81abfe5a409 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -489,4 +489,7 @@ interface IDevicePolicyManager { boolean canProfileOwnerResetPasswordWhenLocked(int userId); void setNextOperationSafety(int operation, boolean safe); + + String getEnrollmentSpecificId(); + void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 43011fce2125..5ccceca9a69d 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4509,6 +4509,17 @@ public abstract class Context { public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; /** + * Official published name of the translation service. + * + * @hide + * @see #getSystemService(String) + */ + // TODO(b/176208267): change it back to translation before S release. + @SystemApi + @SuppressLint("ServiceName") + public static final String TRANSLATION_MANAGER_SERVICE = "transformer"; + + /** * Used for getting content selections and classifications for task snapshots. * * @hide diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e074eab99a7c..17c4d25d82d7 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3406,6 +3406,14 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: + * The device supports translation of text-to-text in multiple languages via integration with + * the system {@link android.service.translation.TranslationService translation provider}. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_TRANSLATION = "android.software.translation"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device implements headtracking suitable for a VR device. */ @SdkConstant(SdkConstantType.FEATURE) diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 36348b365158..8bfbad605420 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -442,6 +442,24 @@ public class NetworkPolicyManager { } /** + * Check that networking is blocked for the given uid. + * + * @param uid The target uid. + * @param meteredNetwork True if the network is metered. + * @return true if networking is blocked for the given uid according to current networking + * policies. + * + * @hide + */ + public boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) { + try { + return mService.isUidNetworkingBlocked(uid, meteredNetwork); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Get multipath preference for the given network. */ public int getMultipathPreference(Network network) { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 6209718e8788..66b99b9ba319 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -40,6 +40,18 @@ import java.util.Set; */ public class NetworkRequest implements Parcelable { /** + * The first requestId value that will be allocated. + * @hide only used by ConnectivityService. + */ + public static final int FIRST_REQUEST_ID = 1; + + /** + * The requestId value that represents the absence of a request. + * @hide only used by ConnectivityService. + */ + public static final int REQUEST_ID_NONE = -1; + + /** * The {@link NetworkCapabilities} that define this request. * @hide */ diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java index bf8ac6e55d8a..ba29a15a91bb 100644 --- a/core/java/android/os/BatteryConsumer.java +++ b/core/java/android/os/BatteryConsumer.java @@ -39,6 +39,11 @@ public abstract class BatteryConsumer { POWER_COMPONENT_USAGE, POWER_COMPONENT_CPU, POWER_COMPONENT_BLUETOOTH, + POWER_COMPONENT_CAMERA, + POWER_COMPONENT_AUDIO, + POWER_COMPONENT_VIDEO, + POWER_COMPONENT_FLASHLIGHT, + POWER_COMPONENT_SYSTEM_SERVICES, }) @Retention(RetentionPolicy.SOURCE) public static @interface PowerComponent { @@ -47,8 +52,13 @@ public abstract class BatteryConsumer { public static final int POWER_COMPONENT_USAGE = 0; public static final int POWER_COMPONENT_CPU = 1; public static final int POWER_COMPONENT_BLUETOOTH = 2; + public static final int POWER_COMPONENT_CAMERA = 3; + public static final int POWER_COMPONENT_AUDIO = 4; + public static final int POWER_COMPONENT_VIDEO = 5; + public static final int POWER_COMPONENT_FLASHLIGHT = 6; + public static final int POWER_COMPONENT_SYSTEM_SERVICES = 7; - public static final int POWER_COMPONENT_COUNT = 3; + public static final int POWER_COMPONENT_COUNT = 8; public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000; public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999; @@ -75,6 +85,8 @@ public abstract class BatteryConsumer { TIME_COMPONENT_CPU, TIME_COMPONENT_CPU_FOREGROUND, TIME_COMPONENT_BLUETOOTH, + TIME_COMPONENT_CAMERA, + TIME_COMPONENT_FLASHLIGHT, }) @Retention(RetentionPolicy.SOURCE) public static @interface TimeComponent { @@ -84,8 +96,12 @@ public abstract class BatteryConsumer { public static final int TIME_COMPONENT_CPU = 1; public static final int TIME_COMPONENT_CPU_FOREGROUND = 2; public static final int TIME_COMPONENT_BLUETOOTH = 3; + public static final int TIME_COMPONENT_CAMERA = 4; + public static final int TIME_COMPONENT_AUDIO = 5; + public static final int TIME_COMPONENT_VIDEO = 6; + public static final int TIME_COMPONENT_FLASHLIGHT = 7; - public static final int TIME_COMPONENT_COUNT = 4; + public static final int TIME_COMPONENT_COUNT = 8; public static final int FIRST_CUSTOM_TIME_COMPONENT_ID = 1000; public static final int LAST_CUSTOM_TIME_COMPONENT_ID = 9999; diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index b57418d751bc..c0b2ada7860c 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -1071,6 +1071,7 @@ public abstract class VibrationEffect implements Parcelable { PRIMITIVE_SLOW_RISE, PRIMITIVE_QUICK_FALL, PRIMITIVE_TICK, + PRIMITIVE_LOW_TICK, }) @Retention(RetentionPolicy.SOURCE) public @interface Primitive {} @@ -1116,6 +1117,12 @@ public abstract class VibrationEffect implements Parcelable { */ // Internally this maps to the HAL constant CompositePrimitive::LIGHT_TICK public static final int PRIMITIVE_TICK = 7; + /** + * This very short low frequency effect should produce a light crisp sensation + * intended to be used repetitively for dynamic feedback. + */ + // Internally this maps to the HAL constant CompositePrimitive::LOW_TICK + public static final int PRIMITIVE_LOW_TICK = 8; private ArrayList<PrimitiveEffect> mEffects = new ArrayList<>(); @@ -1194,7 +1201,7 @@ public abstract class VibrationEffect implements Parcelable { * */ static int checkPrimitive(int primitiveId) { - Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_TICK, + Preconditions.checkArgumentInRange(primitiveId, PRIMITIVE_NOOP, PRIMITIVE_LOW_TICK, "primitiveId"); return primitiveId; } @@ -1223,6 +1230,8 @@ public abstract class VibrationEffect implements Parcelable { return "PRIMITIVE_QUICK_FALL"; case PRIMITIVE_TICK: return "PRIMITIVE_TICK"; + case PRIMITIVE_LOW_TICK: + return "PRIMITIVE_LOW_TICK"; default: return Integer.toString(id); } diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java index 8ac1fc1f23c7..b5abe2a3e311 100644 --- a/core/java/android/os/storage/StorageVolume.java +++ b/core/java/android/os/storage/StorageVolume.java @@ -163,7 +163,7 @@ public final class StorageVolume implements Parcelable { mMaxFileSize = in.readLong(); mOwner = in.readParcelable(null); if (in.readInt() != 0) { - mUuid = StorageManager.convert(in.readString()); + mUuid = StorageManager.convert(in.readString8()); } else { mUuid = null; } diff --git a/core/java/android/service/translation/ITranslationCallback.aidl b/core/java/android/service/translation/ITranslationCallback.aidl new file mode 100644 index 000000000000..333cb577f790 --- /dev/null +++ b/core/java/android/service/translation/ITranslationCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import android.view.translation.TranslationResponse; + +/** + * Interface to receive the result of a {@code TranslationRequest}. + * + * @hide + */ +oneway interface ITranslationCallback { + void onTranslationComplete(in TranslationResponse translationResponse); + void onError(); +} diff --git a/core/java/android/service/translation/ITranslationService.aidl b/core/java/android/service/translation/ITranslationService.aidl new file mode 100644 index 000000000000..6d6f2782ef4b --- /dev/null +++ b/core/java/android/service/translation/ITranslationService.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import android.service.translation.TranslationRequest; +import android.service.translation.ITranslationCallback; +import android.view.translation.TranslationSpec; +import com.android.internal.os.IResultReceiver; + +/** + * System-wide on-device translation service. + * + * <p>Services requests to translate text between different languages. The primary use case for this + * service is automatic translation of text and web views, when the auto Translate feature is + * enabled. + * + * @hide + */ +oneway interface ITranslationService { + void onConnected(); + void onDisconnected(); + void onCreateTranslationSession(in TranslationSpec sourceSpec, in TranslationSpec destSpec, + int sessionId, in IResultReceiver receiver); +} diff --git a/core/java/android/service/translation/OWNERS b/core/java/android/service/translation/OWNERS new file mode 100644 index 000000000000..a1e663aa8ff7 --- /dev/null +++ b/core/java/android/service/translation/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 994311 + +adamhe@google.com +augale@google.com +joannechung@google.com +lpeter@google.com +svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java b/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java new file mode 100644 index 000000000000..345c69c0935d --- /dev/null +++ b/core/java/android/service/translation/OnTranslationResultCallbackWrapper.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.DeadObjectException; +import android.os.RemoteException; +import android.util.Log; +import android.view.translation.TranslationResponse; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Callback to receive the {@link TranslationResponse} on successful translation. + * + * @hide + */ +final class OnTranslationResultCallbackWrapper implements + TranslationService.OnTranslationResultCallback { + + private static final String TAG = "OnTranslationResultCallback"; + + private final @NonNull ITranslationCallback mCallback; + + private AtomicBoolean mCalled; + + /** + * @hide + */ + public OnTranslationResultCallbackWrapper(@NonNull ITranslationCallback callback) { + mCallback = Objects.requireNonNull(callback); + mCalled = new AtomicBoolean(); + } + + @Override + public void onTranslationSuccess(@Nullable TranslationResponse response) { + assertNotCalled(); + if (mCalled.getAndSet(true)) { + throw new IllegalStateException("Already called"); + } + + try { + mCallback.onTranslationComplete(response); + } catch (RemoteException e) { + if (e instanceof DeadObjectException) { + Log.w(TAG, "Process is dead, ignore."); + return; + } + throw e.rethrowAsRuntimeException(); + } + } + + @Override + public void onError() { + assertNotCalled(); + if (mCalled.getAndSet(true)) { + throw new IllegalStateException("Already called"); + } + + try { + mCallback.onError(); + } catch (RemoteException e) { + if (e instanceof DeadObjectException) { + Log.w(TAG, "Process is dead, ignore."); + return; + } + throw e.rethrowAsRuntimeException(); + } + } + + private void assertNotCalled() { + if (mCalled.get()) { + throw new IllegalStateException("Already called"); + } + } +} diff --git a/core/java/android/service/translation/TranslationRequest.aidl b/core/java/android/service/translation/TranslationRequest.aidl new file mode 100644 index 000000000000..9a2d4157696e --- /dev/null +++ b/core/java/android/service/translation/TranslationRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +parcelable TranslationRequest; diff --git a/core/java/android/service/translation/TranslationRequest.java b/core/java/android/service/translation/TranslationRequest.java new file mode 100644 index 000000000000..b8afd7049a82 --- /dev/null +++ b/core/java/android/service/translation/TranslationRequest.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.translation.TranslationSpec; + +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * Internal translation request sent to the {@link android.service.translation.TranslationService} + * which contains the text to be translated. + * + * @hide + */ +@SystemApi +@DataClass(genConstructor = true, genBuilder = true, genToString = true) +public final class TranslationRequest implements Parcelable { + + private final int mRequestId; + @NonNull + private final TranslationSpec mSourceSpec; + @NonNull + private final TranslationSpec mDestSpec; + @NonNull + private final List<android.view.translation.TranslationRequest> mTranslationRequests; + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/translation/TranslationRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public TranslationRequest( + int requestId, + @NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, + @NonNull List<android.view.translation.TranslationRequest> translationRequests) { + this.mRequestId = requestId; + this.mSourceSpec = sourceSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSourceSpec); + this.mDestSpec = destSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mDestSpec); + this.mTranslationRequests = translationRequests; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTranslationRequests); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public int getRequestId() { + return mRequestId; + } + + @DataClass.Generated.Member + public @NonNull TranslationSpec getSourceSpec() { + return mSourceSpec; + } + + @DataClass.Generated.Member + public @NonNull TranslationSpec getDestSpec() { + return mDestSpec; + } + + @DataClass.Generated.Member + public @NonNull List<android.view.translation.TranslationRequest> getTranslationRequests() { + return mTranslationRequests; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "TranslationRequest { " + + "requestId = " + mRequestId + ", " + + "sourceSpec = " + mSourceSpec + ", " + + "destSpec = " + mDestSpec + ", " + + "translationRequests = " + mTranslationRequests + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mRequestId); + dest.writeTypedObject(mSourceSpec, flags); + dest.writeTypedObject(mDestSpec, flags); + dest.writeParcelableList(mTranslationRequests, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ TranslationRequest(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int requestId = in.readInt(); + TranslationSpec sourceSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR); + TranslationSpec destSpec = (TranslationSpec) in.readTypedObject(TranslationSpec.CREATOR); + List<android.view.translation.TranslationRequest> translationRequests = new ArrayList<>(); + in.readParcelableList(translationRequests, android.view.translation.TranslationRequest.class.getClassLoader()); + + this.mRequestId = requestId; + this.mSourceSpec = sourceSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSourceSpec); + this.mDestSpec = destSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mDestSpec); + this.mTranslationRequests = translationRequests; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTranslationRequests); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<TranslationRequest> CREATOR + = new Parcelable.Creator<TranslationRequest>() { + @Override + public TranslationRequest[] newArray(int size) { + return new TranslationRequest[size]; + } + + @Override + public TranslationRequest createFromParcel(@NonNull Parcel in) { + return new TranslationRequest(in); + } + }; + + /** + * A builder for {@link TranslationRequest} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder { + + private int mRequestId; + private @NonNull TranslationSpec mSourceSpec; + private @NonNull TranslationSpec mDestSpec; + private @NonNull List<android.view.translation.TranslationRequest> mTranslationRequests; + + private long mBuilderFieldsSet = 0L; + + public Builder( + int requestId, + @NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, + @NonNull List<android.view.translation.TranslationRequest> translationRequests) { + mRequestId = requestId; + mSourceSpec = sourceSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSourceSpec); + mDestSpec = destSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mDestSpec); + mTranslationRequests = translationRequests; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTranslationRequests); + } + + @DataClass.Generated.Member + public @NonNull Builder setRequestId(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mRequestId = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setSourceSpec(@NonNull TranslationSpec value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mSourceSpec = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setDestSpec(@NonNull TranslationSpec value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mDestSpec = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setTranslationRequests(@NonNull List<android.view.translation.TranslationRequest> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mTranslationRequests = value; + return this; + } + + /** @see #setTranslationRequests */ + @DataClass.Generated.Member + public @NonNull Builder addTranslationRequests(@NonNull android.view.translation.TranslationRequest value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mTranslationRequests == null) setTranslationRequests(new ArrayList<>()); + mTranslationRequests.add(value); + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull TranslationRequest build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; // Mark builder used + + TranslationRequest o = new TranslationRequest( + mRequestId, + mSourceSpec, + mDestSpec, + mTranslationRequests); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x10) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1609966181888L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/service/translation/TranslationRequest.java", + inputSignatures = "private final int mRequestId\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mSourceSpec\nprivate final @android.annotation.NonNull android.view.translation.TranslationSpec mDestSpec\nprivate final @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslationRequests\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=true, genBuilder=true, genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java new file mode 100644 index 000000000000..b0288076376c --- /dev/null +++ b/core/java/android/service/translation/TranslationService.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import static android.view.translation.Translator.EXTRA_SERVICE_BINDER; +import static android.view.translation.Translator.EXTRA_SESSION_ID; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.BaseBundle; +import android.os.Bundle; +import android.os.CancellationSignal; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import android.view.translation.ITranslationDirectManager; +import android.view.translation.TranslationManager; +import android.view.translation.TranslationResponse; +import android.view.translation.TranslationSpec; + +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.SyncResultReceiver; + +/** + * Service for translating text. + * @hide + */ +@SystemApi +public abstract class TranslationService extends Service { + private static final String TAG = "TranslationService"; + + /** + * The {@link Intent} that must be declared as handled by the service. + * + * <p>To be supported, the service must also require the + * {@link android.Manifest.permission#BIND_TRANSLATION_SERVICE} permission so + * that other applications can not abuse it. + */ + public static final String SERVICE_INTERFACE = + "android.service.translation.TranslationService"; + + /** + * Name under which a TranslationService component publishes information about itself. + * + * <p>This meta-data should reference an XML resource containing a + * <code><{@link + * android.R.styleable#TranslationService translation-service}></code> tag. + * + * <p>Here's an example of how to use it on {@code AndroidManifest.xml}: + * TODO: fill in doc example (check CCService/AFService). + */ + public static final String SERVICE_META_DATA = "android.translation_service"; + + private Handler mHandler; + + /** + * Binder to receive calls from system server. + */ + private final ITranslationService mInterface = new ITranslationService.Stub() { + @Override + public void onConnected() { + mHandler.sendMessage(obtainMessage(TranslationService::onConnected, + TranslationService.this)); + } + + @Override + public void onDisconnected() { + mHandler.sendMessage(obtainMessage(TranslationService::onDisconnected, + TranslationService.this)); + } + + @Override + public void onCreateTranslationSession(TranslationSpec sourceSpec, TranslationSpec destSpec, + int sessionId, IResultReceiver receiver) throws RemoteException { + mHandler.sendMessage(obtainMessage(TranslationService::handleOnCreateTranslationSession, + TranslationService.this, sourceSpec, destSpec, sessionId, receiver)); + } + }; + + /** + * Interface definition for a callback to be invoked when the translation is compleled. + */ + public interface OnTranslationResultCallback { + /** + * Notifies the Android System that a translation request + * {@link TranslationService#onTranslationRequest(TranslationRequest, int, + * CancellationSignal, OnTranslationResultCallback)} was successfully fulfilled by the + * service. + * + * <p>This method should always be called, even if the service cannot fulfill the request + * (in which case it should be called with a TranslationResponse with + * {@link android.view.translation.TranslationResponse#TRANSLATION_STATUS_UNKNOWN_ERROR}, + * or {@link android.view.translation.TranslationResponse + * #TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE}). + * + * @param response translation response for the provided request infos. + * + * @throws IllegalStateException if this method was already called. + */ + void onTranslationSuccess(@NonNull TranslationResponse response); + + /** + * TODO: implement javadoc + */ + void onError(); + } + + /** + * Binder that receives calls from the app. + */ + private final ITranslationDirectManager mClientInterface = + new ITranslationDirectManager.Stub() { + // TODO: Implement cancellation signal + @NonNull + private final CancellationSignal mCancellationSignal = new CancellationSignal(); + + @Override + public void onTranslationRequest(TranslationRequest request, int sessionId, + ITranslationCallback callback, IResultReceiver receiver) + throws RemoteException { + // TODO(b/176464808): Currently, the API is used for both sync and async case. + // It may work now, but maybe two methods is more cleaner. To think how to + // define the APIs for these two cases. + final ITranslationCallback cb = callback != null + ? callback + : new ITranslationCallback.Stub() { + @Override + public void onTranslationComplete( + TranslationResponse translationResponse) + throws RemoteException { + receiver.send(0, + SyncResultReceiver.bundleFor(translationResponse)); + } + + @Override + public void onError() throws RemoteException { + //TODO: implement default error callback + } + }; + // TODO(b/176464808): make it a private member of client + final OnTranslationResultCallback translationResultCallback = + new OnTranslationResultCallbackWrapper(cb); + mHandler.sendMessage(obtainMessage(TranslationService::onTranslationRequest, + TranslationService.this, request, sessionId, mCancellationSignal, + translationResultCallback)); + } + + @Override + public void onFinishTranslationSession(int sessionId) throws RemoteException { + mHandler.sendMessage(obtainMessage( + TranslationService::onFinishTranslationSession, + TranslationService.this, sessionId)); + } + }; + + @CallSuper + @Override + public void onCreate() { + super.onCreate(); + mHandler = new Handler(Looper.getMainLooper(), null, true); + BaseBundle.setShouldDefuse(true); + } + + @Override + @Nullable + public final IBinder onBind(@NonNull Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + return mInterface.asBinder(); + } + Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent); + return null; + } + + /** + * Called when the Android system connects to service. + * + * <p>You should generally do initialization here rather than in {@link #onCreate}. + */ + public void onConnected() { + } + + /** + * Called when the Android system disconnects from the service. + * + * <p> At this point this service may no longer be an active {@link TranslationService}. + * It should not make calls on {@link TranslationManager} that requires the caller to be + * the current service. + */ + public void onDisconnected() { + } + + /** + * TODO: fill in javadoc. + * + * @param sourceSpec + * @param destSpec + * @param sessionId + */ + // TODO(b/176464808): the session id won't be unique cross client/server process. Need to find + // solution to make it's safe. + public abstract void onCreateTranslationSession(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId); + + /** + * TODO: fill in javadoc. + * + * @param sessionId + */ + public abstract void onFinishTranslationSession(int sessionId); + + /** + * TODO: fill in javadoc. + * + * @param request + * @param sessionId + * @param callback + * @param cancellationSignal + */ + public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId, + @NonNull CancellationSignal cancellationSignal, + @NonNull OnTranslationResultCallback callback); + + // TODO(b/176464808): Need to handle client dying case + + // TODO(b/176464808): Need to handle the failure case. e.g. if the specs does not support + + private void handleOnCreateTranslationSession(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) { + try { + final Bundle extras = new Bundle(); + extras.putBinder(EXTRA_SERVICE_BINDER, mClientInterface.asBinder()); + extras.putInt(EXTRA_SESSION_ID, sessionId); + resultReceiver.send(0, extras); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException sending client interface: " + e); + } + onCreateTranslationSession(sourceSpec, destSpec, sessionId); + } +} diff --git a/core/java/android/service/translation/TranslationServiceInfo.java b/core/java/android/service/translation/TranslationServiceInfo.java new file mode 100644 index 000000000000..18cc29d12b5f --- /dev/null +++ b/core/java/android/service/translation/TranslationServiceInfo.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.translation; + +import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.AppGlobals; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ServiceInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.RemoteException; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.R; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.PrintWriter; + +/** + * {@link ServiceInfo} and meta-data about an {@link TranslationService}. + * + * @hide + */ +public final class TranslationServiceInfo { + + private static final String TAG = "TranslationServiceInfo"; + private static final String XML_TAG_SERVICE = "translation-service"; + + @NonNull + private final ServiceInfo mServiceInfo; + + @Nullable + private final String mSettingsActivity; + + private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp, + @UserIdInt int userId) throws PackageManager.NameNotFoundException { + int flags = PackageManager.GET_META_DATA; + if (!isTemp) { + flags |= PackageManager.MATCH_SYSTEM_ONLY; + } + + ServiceInfo si = null; + try { + si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId); + } catch (RemoteException e) { + } + if (si == null) { + throw new NameNotFoundException("Could not get serviceInfo for " + + (isTemp ? " (temp)" : "(default system)") + + " " + comp.flattenToShortString()); + } + return si; + } + + @NonNull + public ServiceInfo getServiceInfo() { + return mServiceInfo; + } + + @Nullable + public String getSettingsActivity() { + return mSettingsActivity; + } + + public TranslationServiceInfo(@NonNull Context context, @NonNull ComponentName comp, + boolean isTemporaryService, @UserIdInt int userId) + throws PackageManager.NameNotFoundException { + this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId)); + } + + private TranslationServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) { + // Check for permission. + if (!Manifest.permission.BIND_TRANSLATION_SERVICE.equals(si.permission)) { + Slog.w(TAG, "TranslationServiceInfo from '" + si.packageName + + "' does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + throw new SecurityException("Service does not require permission " + + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + } + + mServiceInfo = si; + + // Get the metadata, if declared. + // TODO: Try to find more easier way to do this. + final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(), + TranslationService.SERVICE_META_DATA); + if (parser == null) { + mSettingsActivity = null; + return; + } + + String settingsActivity = null; + + try { + final Resources resources = context.getPackageManager().getResourcesForApplication( + si.applicationInfo); + + int type = 0; + while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { + type = parser.next(); + } + + if (XML_TAG_SERVICE.equals(parser.getName())) { + final AttributeSet allAttributes = Xml.asAttributeSet(parser); + TypedArray afsAttributes = null; + try { + afsAttributes = resources.obtainAttributes(allAttributes, + com.android.internal.R.styleable.TranslationService); + settingsActivity = afsAttributes.getString( + R.styleable.ContentCaptureService_settingsActivity); + } finally { + if (afsAttributes != null) { + afsAttributes.recycle(); + } + } + } else { + Log.e(TAG, "Meta-data does not start with translation-service tag"); + } + } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) { + Log.e(TAG, "Error parsing auto fill service meta-data", e); + } + + mSettingsActivity = settingsActivity; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append(getClass().getSimpleName()); + builder.append("[").append(mServiceInfo); + builder.append(", settings:").append(mSettingsActivity); + return builder.toString(); + } + + /** + * Dumps the service information. + */ + public void dump(@NonNull String prefix, @NonNull PrintWriter pw) { + pw.print(prefix); + pw.print("Component: "); + pw.println(getServiceInfo().getComponentName()); + pw.print(prefix); + pw.print("Settings: "); + pw.println(mSettingsActivity); + } +} diff --git a/core/java/android/view/translation/ITranslationDirectManager.aidl b/core/java/android/view/translation/ITranslationDirectManager.aidl new file mode 100644 index 000000000000..358f99a5104b --- /dev/null +++ b/core/java/android/view/translation/ITranslationDirectManager.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.service.translation.TranslationRequest; +import android.service.translation.ITranslationCallback; +import com.android.internal.os.IResultReceiver; + +/** + * Interface between an app (TranslationManager / Translator) and the remote TranslationService + * providing the TranslationService implementation. + * + * @hide + */ +oneway interface ITranslationDirectManager { + void onTranslationRequest(in TranslationRequest request, int sessionId, + in ITranslationCallback callback, in IResultReceiver receiver); + void onFinishTranslationSession(int sessionId); +} diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl new file mode 100644 index 000000000000..73addf4d1894 --- /dev/null +++ b/core/java/android/view/translation/ITranslationManager.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.service.translation.TranslationRequest; +import android.view.translation.TranslationSpec; +import com.android.internal.os.IResultReceiver; + +/** + * Mediator between apps being translated and translation service implementation. + * + * {@hide} + */ +oneway interface ITranslationManager { + void getSupportedLocales(in IResultReceiver receiver, int userId); + void onSessionCreated(in TranslationSpec sourceSpec, in TranslationSpec destSpec, + int sessionId, in IResultReceiver receiver, int userId); +} diff --git a/core/java/android/view/translation/OWNERS b/core/java/android/view/translation/OWNERS new file mode 100644 index 000000000000..a1e663aa8ff7 --- /dev/null +++ b/core/java/android/view/translation/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 994311 + +adamhe@google.com +augale@google.com +joannechung@google.com +lpeter@google.com +svetoslavganov@google.com +tymtsai@google.com diff --git a/core/java/android/view/translation/TranslationData.aidl b/core/java/android/view/translation/TranslationData.aidl new file mode 100644 index 000000000000..40f21a6b3d4e --- /dev/null +++ b/core/java/android/view/translation/TranslationData.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +parcelable TranslationData; diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java new file mode 100644 index 000000000000..6554e1a1db54 --- /dev/null +++ b/core/java/android/view/translation/TranslationManager.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.RequiresFeature; +import android.annotation.SystemService; +import android.annotation.WorkerThread; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.service.translation.TranslationService; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Pair; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.SyncResultReceiver; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The {@link TranslationManager} class provides ways for apps to integrate and use the + * translation framework. + * + * <p>The TranslationManager manages {@link Translator}s and help bridge client calls to + * the server {@link android.service.translation.TranslationService} </p> + */ +@SystemService(Context.TRANSLATION_MANAGER_SERVICE) +@RequiresFeature(PackageManager.FEATURE_TRANSLATION) +public final class TranslationManager { + + private static final String TAG = "TranslationManager"; + + /** + * Timeout for calls to system_server. + */ + static final int SYNC_CALLS_TIMEOUT_MS = 5000; + /** + * The result code from result receiver success. + * @hide + */ + public static final int STATUS_SYNC_CALL_SUCCESS = 1; + /** + * The result code from result receiver fail. + * @hide + */ + public static final int STATUS_SYNC_CALL_FAIL = 2; + + private static final Random ID_GENERATOR = new Random(); + private final Object mLock = new Object(); + + @NonNull + private final Context mContext; + + private final ITranslationManager mService; + + @Nullable + @GuardedBy("mLock") + private ITranslationDirectManager mDirectServiceBinder; + + @NonNull + @GuardedBy("mLock") + private final SparseArray<Translator> mTranslators = new SparseArray<>(); + + @NonNull + @GuardedBy("mLock") + private final ArrayMap<Pair<TranslationSpec, TranslationSpec>, Integer> mTranslatorIds = + new ArrayMap<>(); + + @NonNull + private final Handler mHandler; + + private static final AtomicInteger sAvailableRequestId = new AtomicInteger(1); + + /** + * @hide + */ + public TranslationManager(@NonNull Context context, ITranslationManager service) { + mContext = Objects.requireNonNull(context, "context cannot be null"); + mService = service; + + mHandler = Handler.createAsync(Looper.getMainLooper()); + } + + /** + * Create a Translator for translation. + * + * <p><strong>NOTE: </strong>Call on a worker thread. + * + * @param sourceSpec {@link TranslationSpec} for the data to be translated. + * @param destSpec {@link TranslationSpec} for the translated data. + * @return a {@link Translator} to be used for calling translation APIs. + */ + @Nullable + @WorkerThread + public Translator createTranslator(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec) { + Objects.requireNonNull(sourceSpec, "sourceSpec cannot be null"); + Objects.requireNonNull(sourceSpec, "destSpec cannot be null"); + + synchronized (mLock) { + // TODO(b/176464808): Disallow multiple Translator now, it will throw + // IllegalStateException. Need to discuss if we can allow multiple Translators. + final Pair<TranslationSpec, TranslationSpec> specs = new Pair<>(sourceSpec, destSpec); + if (mTranslatorIds.containsKey(specs)) { + return mTranslators.get(mTranslatorIds.get(specs)); + } + + int translatorId; + do { + translatorId = Math.abs(ID_GENERATOR.nextInt()); + } while (translatorId == 0 || mTranslators.indexOfKey(translatorId) >= 0); + + final Translator newTranslator = new Translator(mContext, sourceSpec, destSpec, + translatorId, this, mHandler, mService); + // Start the Translator session and wait for the result + newTranslator.start(); + try { + if (!newTranslator.isSessionCreated()) { + return null; + } + mTranslators.put(translatorId, newTranslator); + mTranslatorIds.put(specs, translatorId); + return newTranslator; + } catch (Translator.ServiceBinderReceiver.TimeoutException e) { + // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor + // public and use it. + Log.e(TAG, "Timed out getting create session: " + e); + return null; + } + } + } + + /** + * Returns a list of locales supported by the {@link TranslationService}. + * + * <p><strong>NOTE: </strong>Call on a worker thread. + * + * TODO: Change to correct language/locale format + */ + @NonNull + @WorkerThread + public List<String> getSupportedLocales() { + try { + // TODO: implement it + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); + mService.getSupportedLocales(receiver, mContext.getUserId()); + int resutCode = receiver.getIntResult(); + if (resutCode != STATUS_SYNC_CALL_SUCCESS) { + return Collections.emptyList(); + } + return receiver.getParcelableResult(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Timed out getting supported locales: " + e); + return Collections.emptyList(); + } + } + + void removeTranslator(int id) { + synchronized (mLock) { + mTranslators.remove(id); + for (int i = 0; i < mTranslatorIds.size(); i++) { + if (mTranslatorIds.valueAt(i) == id) { + mTranslatorIds.removeAt(i); + break; + } + } + } + } + + AtomicInteger getAvailableRequestId() { + synchronized (mLock) { + return sAvailableRequestId; + } + } +} diff --git a/core/java/android/view/translation/TranslationRequest.aidl b/core/java/android/view/translation/TranslationRequest.aidl new file mode 100644 index 000000000000..c34bf3011462 --- /dev/null +++ b/core/java/android/view/translation/TranslationRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +parcelable TranslationRequest; diff --git a/core/java/android/view/translation/TranslationRequest.java b/core/java/android/view/translation/TranslationRequest.java new file mode 100644 index 000000000000..a5e3f758ba9f --- /dev/null +++ b/core/java/android/view/translation/TranslationRequest.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; +import android.view.autofill.AutofillId; + +import com.android.internal.util.DataClass; + +/** + * Wrapper class for data to be translated by {@link android.service.translation.TranslationService} + */ +@DataClass(genToString = true, genBuilder = true) +public final class TranslationRequest implements Parcelable { + + @Nullable + private final AutofillId mAutofillId; + + @Nullable + private final CharSequence mTranslationText; + + public TranslationRequest(@Nullable CharSequence text) { + mAutofillId = null; + mTranslationText = text; + } + + private static CharSequence defaultTranslationText() { + return null; + } + + private static AutofillId defaultAutofillId() { + return null; + } + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + /* package-private */ TranslationRequest( + @Nullable AutofillId autofillId, + @Nullable CharSequence translationText) { + this.mAutofillId = autofillId; + this.mTranslationText = translationText; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @Nullable AutofillId getAutofillId() { + return mAutofillId; + } + + @DataClass.Generated.Member + public @Nullable CharSequence getTranslationText() { + return mTranslationText; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "TranslationRequest { " + + "autofillId = " + mAutofillId + ", " + + "translationText = " + mTranslationText + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mAutofillId != null) flg |= 0x1; + if (mTranslationText != null) flg |= 0x2; + dest.writeByte(flg); + if (mAutofillId != null) dest.writeTypedObject(mAutofillId, flags); + if (mTranslationText != null) dest.writeCharSequence(mTranslationText); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ TranslationRequest(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + AutofillId autofillId = (flg & 0x1) == 0 ? null : (AutofillId) in.readTypedObject(AutofillId.CREATOR); + CharSequence translationText = (flg & 0x2) == 0 ? null : (CharSequence) in.readCharSequence(); + + this.mAutofillId = autofillId; + this.mTranslationText = translationText; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<TranslationRequest> CREATOR + = new Parcelable.Creator<TranslationRequest>() { + @Override + public TranslationRequest[] newArray(int size) { + return new TranslationRequest[size]; + } + + @Override + public TranslationRequest createFromParcel(@NonNull android.os.Parcel in) { + return new TranslationRequest(in); + } + }; + + /** + * A builder for {@link TranslationRequest} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder { + + private @Nullable AutofillId mAutofillId; + private @Nullable CharSequence mTranslationText; + + private long mBuilderFieldsSet = 0L; + + public Builder() { + } + + @DataClass.Generated.Member + public @NonNull Builder setAutofillId(@NonNull AutofillId value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mAutofillId = value; + return this; + } + + @DataClass.Generated.Member + public @NonNull Builder setTranslationText(@NonNull CharSequence value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mTranslationText = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull TranslationRequest build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mAutofillId = defaultAutofillId(); + } + if ((mBuilderFieldsSet & 0x2) == 0) { + mTranslationText = defaultTranslationText(); + } + TranslationRequest o = new TranslationRequest( + mAutofillId, + mTranslationText); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x4) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1610060189421L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/view/translation/TranslationRequest.java", + inputSignatures = "private final @android.annotation.Nullable android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.Nullable java.lang.CharSequence mTranslationText\nprivate static java.lang.CharSequence defaultTranslationText()\nprivate static android.view.autofill.AutofillId defaultAutofillId()\nclass TranslationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genBuilder=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/translation/TranslationResponse.aidl b/core/java/android/view/translation/TranslationResponse.aidl new file mode 100644 index 000000000000..e5350bb54dc2 --- /dev/null +++ b/core/java/android/view/translation/TranslationResponse.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +parcelable TranslationResponse; diff --git a/core/java/android/view/translation/TranslationResponse.java b/core/java/android/view/translation/TranslationResponse.java new file mode 100644 index 000000000000..d29063fbd914 --- /dev/null +++ b/core/java/android/view/translation/TranslationResponse.java @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.service.translation.TranslationService; + +import com.android.internal.util.DataClass; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Response from the {@link TranslationService}, which contains the translated result. + */ +@DataClass(genBuilder = true, genToString = true, genHiddenConstDefs = true) +public final class TranslationResponse implements Parcelable { + + /** + * The {@link TranslationService} was successful in translating. + */ + public static final int TRANSLATION_STATUS_SUCCESS = 0; + /** + * The {@link TranslationService} returned unknown translation result. + */ + public static final int TRANSLATION_STATUS_UNKNOWN_ERROR = 1; + /** + * The language of the request is not available to be translated. + */ + public static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE = 2; + + /** + * The translation result status code. + */ + private final @TranslationStatus int mTranslationStatus; + /** + * The translation results. If there is no translation result, set it with an empty list. + */ + @NonNull + private List<TranslationRequest> mTranslations = new ArrayList(); + + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationResponse.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** @hide */ + @IntDef(prefix = "TRANSLATION_STATUS_", value = { + TRANSLATION_STATUS_SUCCESS, + TRANSLATION_STATUS_UNKNOWN_ERROR, + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + }) + @Retention(RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface TranslationStatus {} + + /** @hide */ + @DataClass.Generated.Member + public static String translationStatusToString(@TranslationStatus int value) { + switch (value) { + case TRANSLATION_STATUS_SUCCESS: + return "TRANSLATION_STATUS_SUCCESS"; + case TRANSLATION_STATUS_UNKNOWN_ERROR: + return "TRANSLATION_STATUS_UNKNOWN_ERROR"; + case TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE: + return "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE"; + default: return Integer.toHexString(value); + } + } + + @DataClass.Generated.Member + /* package-private */ TranslationResponse( + @TranslationStatus int translationStatus, + @NonNull List<TranslationRequest> translations) { + this.mTranslationStatus = translationStatus; + + if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS) + && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR) + && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) { + throw new java.lang.IllegalArgumentException( + "translationStatus was " + mTranslationStatus + " but must be one of: " + + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), " + + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), " + + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")"); + } + + this.mTranslations = translations; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTranslations); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The translation result status code. + */ + @DataClass.Generated.Member + public @TranslationStatus int getTranslationStatus() { + return mTranslationStatus; + } + + /** + * The translation results. If there is no translation result, set it with an empty list. + */ + @DataClass.Generated.Member + public @NonNull List<TranslationRequest> getTranslations() { + return mTranslations; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "TranslationResponse { " + + "translationStatus = " + translationStatusToString(mTranslationStatus) + ", " + + "translations = " + mTranslations + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mTranslationStatus); + dest.writeParcelableList(mTranslations, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ TranslationResponse(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int translationStatus = in.readInt(); + List<TranslationRequest> translations = new ArrayList<>(); + in.readParcelableList(translations, TranslationRequest.class.getClassLoader()); + + this.mTranslationStatus = translationStatus; + + if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS) + && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR) + && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) { + throw new java.lang.IllegalArgumentException( + "translationStatus was " + mTranslationStatus + " but must be one of: " + + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), " + + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), " + + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")"); + } + + this.mTranslations = translations; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mTranslations); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<TranslationResponse> CREATOR + = new Parcelable.Creator<TranslationResponse>() { + @Override + public TranslationResponse[] newArray(int size) { + return new TranslationResponse[size]; + } + + @Override + public TranslationResponse createFromParcel(@NonNull Parcel in) { + return new TranslationResponse(in); + } + }; + + /** + * A builder for {@link TranslationResponse} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder { + + private @TranslationStatus int mTranslationStatus; + private @NonNull List<TranslationRequest> mTranslations; + + private long mBuilderFieldsSet = 0L; + + /** + * Creates a new Builder. + * + * @param translationStatus + * The translation result status code. + */ + public Builder( + @TranslationStatus int translationStatus) { + mTranslationStatus = translationStatus; + + if (!(mTranslationStatus == TRANSLATION_STATUS_SUCCESS) + && !(mTranslationStatus == TRANSLATION_STATUS_UNKNOWN_ERROR) + && !(mTranslationStatus == TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE)) { + throw new java.lang.IllegalArgumentException( + "translationStatus was " + mTranslationStatus + " but must be one of: " + + "TRANSLATION_STATUS_SUCCESS(" + TRANSLATION_STATUS_SUCCESS + "), " + + "TRANSLATION_STATUS_UNKNOWN_ERROR(" + TRANSLATION_STATUS_UNKNOWN_ERROR + "), " + + "TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE(" + TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE + ")"); + } + + } + + /** + * The translation result status code. + */ + @DataClass.Generated.Member + public @NonNull Builder setTranslationStatus(@TranslationStatus int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mTranslationStatus = value; + return this; + } + + /** + * The translation results. If there is no translation result, set it with an empty list. + */ + @DataClass.Generated.Member + public @NonNull Builder setTranslations(@NonNull List<TranslationRequest> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mTranslations = value; + return this; + } + + /** @see #setTranslations */ + @DataClass.Generated.Member + public @NonNull Builder addTranslations(@NonNull TranslationRequest value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mTranslations == null) setTranslations(new ArrayList<>()); + mTranslations.add(value); + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull TranslationResponse build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; // Mark builder used + + if ((mBuilderFieldsSet & 0x2) == 0) { + mTranslations = new ArrayList(); + } + TranslationResponse o = new TranslationResponse( + mTranslationStatus, + mTranslations); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x4) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1609973911361L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/view/translation/TranslationResponse.java", + inputSignatures = "public static final int TRANSLATION_STATUS_SUCCESS\npublic static final int TRANSLATION_STATUS_UNKNOWN_ERROR\npublic static final int TRANSLATION_STATUS_LANGUAGE_UNAVAILABLE\nprivate final @android.view.translation.TranslationResponse.TranslationStatus int mTranslationStatus\nprivate @android.annotation.NonNull java.util.List<android.view.translation.TranslationRequest> mTranslations\nclass TranslationResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genHiddenConstDefs=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/translation/TranslationSpec.aidl b/core/java/android/view/translation/TranslationSpec.aidl new file mode 100644 index 000000000000..875d798370d4 --- /dev/null +++ b/core/java/android/view/translation/TranslationSpec.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +parcelable TranslationSpec; diff --git a/core/java/android/view/translation/TranslationSpec.java b/core/java/android/view/translation/TranslationSpec.java new file mode 100644 index 000000000000..ab1bc477e0fd --- /dev/null +++ b/core/java/android/view/translation/TranslationSpec.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Specs and additional info for the translation data. + * + * <p>This spec help specify information such as the language/locale for the translation, as well + * as the data format for the translation (text, audio, etc.)</p> + */ +@DataClass(genEqualsHashCode = true, genHiddenConstDefs = true) +public final class TranslationSpec implements Parcelable { + + /** Data format for translation is text. */ + public static final int DATA_FORMAT_TEXT = 1; + + /** @hide */ + @android.annotation.IntDef(prefix = "DATA_FORMAT_", value = { + DATA_FORMAT_TEXT + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface DataFormat {} + + /** + * String representation of language codes e.g. "en", "es", etc. + */ + private final @NonNull String mLanguage; + + private final @DataFormat int mDataFormat; + + + + // Code below generated by codegen v1.0.22. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/TranslationSpec.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new TranslationSpec. + * + * @param language + * String representation of language codes e.g. "en", "es", etc. + */ + @DataClass.Generated.Member + public TranslationSpec( + @NonNull String language, + @DataFormat int dataFormat) { + this.mLanguage = language; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mLanguage); + this.mDataFormat = dataFormat; + com.android.internal.util.AnnotationValidations.validate( + DataFormat.class, null, mDataFormat); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * String representation of language codes e.g. "en", "es", etc. + */ + @DataClass.Generated.Member + public @NonNull String getLanguage() { + return mLanguage; + } + + @DataClass.Generated.Member + public @DataFormat int getDataFormat() { + return mDataFormat; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@android.annotation.Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(TranslationSpec other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + TranslationSpec that = (TranslationSpec) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mLanguage, that.mLanguage) + && mDataFormat == that.mDataFormat; + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mLanguage); + _hash = 31 * _hash + mDataFormat; + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeString(mLanguage); + dest.writeInt(mDataFormat); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ TranslationSpec(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + String language = in.readString(); + int dataFormat = in.readInt(); + + this.mLanguage = language; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mLanguage); + this.mDataFormat = dataFormat; + com.android.internal.util.AnnotationValidations.validate( + DataFormat.class, null, mDataFormat); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<TranslationSpec> CREATOR + = new Parcelable.Creator<TranslationSpec>() { + @Override + public TranslationSpec[] newArray(int size) { + return new TranslationSpec[size]; + } + + @Override + public TranslationSpec createFromParcel(@NonNull Parcel in) { + return new TranslationSpec(in); + } + }; + + @DataClass.Generated( + time = 1609964630624L, + codegenVersion = "1.0.22", + sourceFile = "frameworks/base/core/java/android/view/translation/TranslationSpec.java", + inputSignatures = "public static final int DATA_FORMAT_TEXT\nprivate final @android.annotation.NonNull java.lang.String mLanguage\nprivate final @android.view.translation.TranslationSpec.DataFormat int mDataFormat\nclass TranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genHiddenConstDefs=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java new file mode 100644 index 000000000000..675f32b19d17 --- /dev/null +++ b/core/java/android/view/translation/Translator.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.translation; + +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; +import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.WorkerThread; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.SyncResultReceiver; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * The {@link Translator} for translation, defined by a source and a dest {@link TranslationSpec}. + */ +@SuppressLint("NotCloseable") +public class Translator { + + private static final String TAG = "Translator"; + + // TODO: make this configurable and cross the Translation component + private static boolean sDEBUG = false; + + private final Object mLock = new Object(); + + private int mId; + + @NonNull + private final Context mContext; + + @NonNull + private final TranslationSpec mSourceSpec; + + @NonNull + private final TranslationSpec mDestSpec; + + @NonNull + private final TranslationManager mManager; + + @NonNull + private final Handler mHandler; + + /** + * Interface to the system_server binder object. + */ + private ITranslationManager mSystemServerBinder; + + /** + * Direct interface to the TranslationService binder object. + */ + @Nullable + private ITranslationDirectManager mDirectServiceBinder; + + @NonNull + private final ServiceBinderReceiver mServiceBinderReceiver; + + @GuardedBy("mLock") + private boolean mDestroyed; + + /** + * Name of the {@link IResultReceiver} extra used to pass the binder interface to Translator. + * @hide + */ + public static final String EXTRA_SERVICE_BINDER = "binder"; + /** + * Name of the extra used to pass the session id to Translator. + * @hide + */ + public static final String EXTRA_SESSION_ID = "sessionId"; + + static class ServiceBinderReceiver extends IResultReceiver.Stub { + private final WeakReference<Translator> mTranslator; + private final CountDownLatch mLatch = new CountDownLatch(1); + private int mSessionId; + + ServiceBinderReceiver(Translator translator) { + mTranslator = new WeakReference<>(translator); + } + + int getSessionStateResult() throws TimeoutException { + try { + if (!mLatch.await(SYNC_CALLS_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + throw new TimeoutException( + "Session not created in " + SYNC_CALLS_TIMEOUT_MS + "ms"); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new TimeoutException("Session not created because interrupted"); + } + return mSessionId; + } + + @Override + public void send(int resultCode, Bundle resultData) { + if (resultCode == STATUS_SYNC_CALL_FAIL) { + mLatch.countDown(); + return; + } + mSessionId = resultData.getInt(EXTRA_SESSION_ID); + final Translator translator = mTranslator.get(); + if (translator == null) { + Log.w(TAG, "received result after session is finished"); + return; + } + final IBinder binder; + if (resultData != null) { + binder = resultData.getBinder(EXTRA_SERVICE_BINDER); + if (binder == null) { + Log.wtf(TAG, "No " + EXTRA_SERVICE_BINDER + " extra result"); + return; + } + } else { + binder = null; + } + translator.setServiceBinder(binder); + mLatch.countDown(); + } + + // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public + // and use it. + static final class TimeoutException extends Exception { + private TimeoutException(String msg) { + super(msg); + } + } + } + + /** + * Create the Translator. + * + * @hide + */ + public Translator(@NonNull Context context, + @NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, + @NonNull TranslationManager translationManager, @NonNull Handler handler, + @Nullable ITranslationManager systemServerBinder) { + mContext = context; + mSourceSpec = sourceSpec; + mDestSpec = destSpec; + mId = sessionId; + mManager = translationManager; + mHandler = handler; + mSystemServerBinder = systemServerBinder; + mServiceBinderReceiver = new ServiceBinderReceiver(this); + } + + /** + * Starts this Translator session. + */ + void start() { + try { + mSystemServerBinder.onSessionCreated(mSourceSpec, mDestSpec, mId, + mServiceBinderReceiver, mContext.getUserId()); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling startSession(): " + e); + } + } + + /** + * Wait this Translator session created. + * + * @return {@code true} if the session is created successfully. + */ + boolean isSessionCreated() throws ServiceBinderReceiver.TimeoutException { + int receivedId = mServiceBinderReceiver.getSessionStateResult(); + return receivedId > 0; + } + + private int getNextRequestId() { + // Get from manager to keep the request id unique to different Translators + return mManager.getAvailableRequestId().getAndIncrement(); + } + + private void setServiceBinder(@Nullable IBinder binder) { + synchronized (mLock) { + if (mDirectServiceBinder != null) { + return; + } + if (binder != null) { + mDirectServiceBinder = ITranslationDirectManager.Stub.asInterface(binder); + } + } + } + + /** @hide */ + public int getTranslatorId() { + return mId; + } + + /** + * Requests a translation for the provided {@link TranslationRequest} using the Translator's + * source spec and destination spec. + * + * <p><strong>NOTE: </strong>Call on a worker thread. + * + * @param request {@link TranslationRequest} request to be translated. + * + * @return {@link TranslationRequest} containing translated request, + * or null if translation could not be done. + * @throws IllegalStateException if this TextClassification session was destroyed when calls + */ + @Nullable + @WorkerThread + public TranslationResponse translate(@NonNull TranslationRequest request) { + Objects.requireNonNull(request, "Translation request cannot be null"); + if (isDestroyed()) { + // TODO(b/176464808): Disallow multiple Translator now, it will throw + // IllegalStateException. Need to discuss if we can allow multiple Translators. + throw new IllegalStateException( + "This translator has been destroyed"); + } + final ArrayList<TranslationRequest> requests = new ArrayList<>(); + requests.add(request); + final android.service.translation.TranslationRequest internalRequest = + new android.service.translation.TranslationRequest + .Builder(getNextRequestId(), mSourceSpec, mDestSpec, requests) + .build(); + + TranslationResponse response = null; + try { + final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); + mDirectServiceBinder.onTranslationRequest(internalRequest, mId, null, receiver); + + response = receiver.getParcelableResult(); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling requestTranslate(): " + e); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Timed out calling requestTranslate: " + e); + } + if (sDEBUG) { + Log.v(TAG, "Receive translation response: " + response); + } + return response; + } + + /** + * Destroy this Translator. + */ + public void destroy() { + synchronized (mLock) { + if (mDestroyed) { + return; + } + mDestroyed = true; + try { + mDirectServiceBinder.onFinishTranslationSession(mId); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException calling onSessionFinished"); + } + mDirectServiceBinder = null; + mManager.removeTranslator(mId); + } + } + + /** + * Returns whether or not this Translator has been destroyed. + * + * @see #destroy() + */ + public boolean isDestroyed() { + synchronized (mLock) { + return mDestroyed; + } + } + + // TODO: add methods for UI-toolkit case. +} diff --git a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java index 670ca9f6091e..03fe4551c249 100644 --- a/core/java/com/android/internal/compat/CompatibilityChangeInfo.java +++ b/core/java/com/android/internal/compat/CompatibilityChangeInfo.java @@ -32,6 +32,7 @@ public class CompatibilityChangeInfo implements Parcelable { private final boolean mDisabled; private final boolean mLoggingOnly; private final @Nullable String mDescription; + private final boolean mOverridable; public long getId() { return mChangeId; @@ -58,9 +59,13 @@ public class CompatibilityChangeInfo implements Parcelable { return mDescription; } + public boolean getOverridable() { + return mOverridable; + } + public CompatibilityChangeInfo( Long changeId, String name, int enableAfterTargetSdk, int enableSinceTargetSdk, - boolean disabled, boolean loggingOnly, String description) { + boolean disabled, boolean loggingOnly, String description, boolean overridable) { this.mChangeId = changeId; this.mName = name; if (enableAfterTargetSdk > 0) { @@ -75,6 +80,7 @@ public class CompatibilityChangeInfo implements Parcelable { this.mDisabled = disabled; this.mLoggingOnly = loggingOnly; this.mDescription = description; + this.mOverridable = overridable; } public CompatibilityChangeInfo(CompatibilityChangeInfo other) { @@ -84,6 +90,7 @@ public class CompatibilityChangeInfo implements Parcelable { this.mDisabled = other.mDisabled; this.mLoggingOnly = other.mLoggingOnly; this.mDescription = other.mDescription; + this.mOverridable = other.mOverridable; } private CompatibilityChangeInfo(Parcel in) { @@ -93,6 +100,7 @@ public class CompatibilityChangeInfo implements Parcelable { mDisabled = in.readBoolean(); mLoggingOnly = in.readBoolean(); mDescription = in.readString(); + mOverridable = in.readBoolean(); } @Override @@ -108,6 +116,7 @@ public class CompatibilityChangeInfo implements Parcelable { dest.writeBoolean(mDisabled); dest.writeBoolean(mLoggingOnly); dest.writeString(mDescription); + dest.writeBoolean(mOverridable); } @Override @@ -126,6 +135,9 @@ public class CompatibilityChangeInfo implements Parcelable { if (getLoggingOnly()) { sb.append("; loggingOnly"); } + if (getOverridable()) { + sb.append("; overridable"); + } return sb.append(")").toString(); } @@ -143,8 +155,8 @@ public class CompatibilityChangeInfo implements Parcelable { && this.mEnableSinceTargetSdk == that.mEnableSinceTargetSdk && this.mDisabled == that.mDisabled && this.mLoggingOnly == that.mLoggingOnly - && this.mDescription.equals(that.mDescription); - + && this.mDescription.equals(that.mDescription) + && this.mOverridable == that.mOverridable; } public static final Parcelable.Creator<CompatibilityChangeInfo> CREATOR = diff --git a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java index 9c3bb761b9f7..6609ebe49bf6 100644 --- a/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java +++ b/core/java/com/android/internal/os/AmbientDisplayPowerCalculator.java @@ -16,7 +16,11 @@ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.SystemBatteryConsumer; import android.os.UserHandle; import android.util.SparseArray; @@ -26,11 +30,30 @@ import java.util.List; * Estimates power consumed by the ambient display */ public class AmbientDisplayPowerCalculator extends PowerCalculator { - - private final PowerProfile mPowerProfile; + private final UsageBasedPowerEstimator mPowerEstimator; public AmbientDisplayPowerCalculator(PowerProfile powerProfile) { - mPowerProfile = powerProfile; + mPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY)); + } + + /** + * Ambient display power is the additional power the screen takes while in ambient display/ + * screen doze/always-on display (interchangeable terms) mode. + */ + @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray<UserHandle> asUsers) { + final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + if (powerMah > 0) { + builder.getOrCreateSystemBatteryConsumerBuilder( + SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah) + .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs); + } } /** @@ -42,16 +65,18 @@ public class AmbientDisplayPowerCalculator extends PowerCalculator { @Override public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - - long ambientDisplayMs = batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000; - double power = mPowerProfile.getAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY) - * ambientDisplayMs / (60 * 60 * 1000); - if (power > 0) { + final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + if (powerMah > 0) { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.AMBIENT_DISPLAY, null, 0); - bs.usagePowerMah = power; - bs.usageTimeMs = ambientDisplayMs; + bs.usagePowerMah = powerMah; + bs.usageTimeMs = durationMs; bs.sumPower(); sippers.add(bs); } } + + private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { + return batteryStats.getScreenDozeTime(rawRealtimeUs, statsType) / 1000; + } } diff --git a/core/java/com/android/internal/os/AudioPowerCalculator.java b/core/java/com/android/internal/os/AudioPowerCalculator.java new file mode 100644 index 000000000000..79b331da9c8a --- /dev/null +++ b/core/java/com/android/internal/os/AudioPowerCalculator.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.os.BatteryConsumer; +import android.os.BatteryStats; +import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; + +/** + * A {@link PowerCalculator} to calculate power consumed by audio hardware. + * + * Also see {@link PowerProfile#POWER_AUDIO}. + */ +public class AudioPowerCalculator extends PowerCalculator { + // Calculate audio power usage, an estimate based on the average power routed to different + // components like speaker, bluetooth, usb-c, earphone, etc. + // TODO(b/175344313): improve the model by taking into account different audio routes + private final UsageBasedPowerEstimator mPowerEstimator; + + public AudioPowerCalculator(PowerProfile powerProfile) { + mPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_AUDIO)); + } + + @Override + protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long durationMs = mPowerEstimator.calculateDuration(u.getAudioTurnedOnTimer(), + rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO, powerMah); + } +} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 93dff9f76df1..33aa19078c9f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -873,7 +873,9 @@ public class BatteryStatsImpl extends BatteryStats { protected StopwatchTimer mScreenDozeTimer; int mScreenBrightnessBin = -1; - final StopwatchTimer[] mScreenBrightnessTimer = new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + protected final StopwatchTimer[] mScreenBrightnessTimer = + new StopwatchTimer[NUM_SCREEN_BRIGHTNESS_BINS]; boolean mPretendScreenOff; diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 9904d301ef72..e5d64a0e3c84 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -66,7 +66,8 @@ public class BatteryUsageStatsProvider { mContext.getSystemService(SensorManager.class))); mPowerCalculators.add(new CameraPowerCalculator(mPowerProfile)); mPowerCalculators.add(new FlashlightPowerCalculator(mPowerProfile)); - mPowerCalculators.add(new MediaPowerCalculator(mPowerProfile)); + mPowerCalculators.add(new AudioPowerCalculator(mPowerProfile)); + mPowerCalculators.add(new VideoPowerCalculator(mPowerProfile)); mPowerCalculators.add(new PhonePowerCalculator(mPowerProfile)); mPowerCalculators.add(new ScreenPowerCalculator(mPowerProfile)); mPowerCalculators.add(new AmbientDisplayPowerCalculator(mPowerProfile)); diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java index f5690e0de38f..4c3b950ff715 100644 --- a/core/java/com/android/internal/os/BluetoothPowerCalculator.java +++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java @@ -29,8 +29,8 @@ import android.util.SparseArray; import java.util.List; public class BluetoothPowerCalculator extends PowerCalculator { - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private static final String TAG = "BluetoothPowerCalc"; + private static final boolean DEBUG = BatteryStatsHelper.DEBUG; private final double mIdleMa; private final double mRxMa; private final double mTxMa; @@ -41,11 +41,6 @@ public class BluetoothPowerCalculator extends PowerCalculator { public double powerMah; } - // Objects used for passing calculation results. Fields are used to avoid allocations. - private final PowerAndDuration mUidPowerAndDuration = new PowerAndDuration(); - private final PowerAndDuration mTotalPowerAndDuration = new PowerAndDuration(); - private final PowerAndDuration mSystemPowerAndDuration = new PowerAndDuration(); - public BluetoothPowerCalculator(PowerProfile profile) { mIdleMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE); mRxMa = profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX); @@ -61,8 +56,7 @@ public class BluetoothPowerCalculator extends PowerCalculator { return; } - mTotalPowerAndDuration.durationMs = 0; - mTotalPowerAndDuration.powerMah = 0; + final PowerAndDuration total = new PowerAndDuration(); SystemBatteryConsumer.Builder systemBatteryConsumerBuilder = builder.getOrCreateSystemBatteryConsumerBuilder( @@ -72,24 +66,25 @@ public class BluetoothPowerCalculator extends PowerCalculator { builder.getUidBatteryConsumerBuilders(); for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); - calculateApp(app); + calculateApp(app, total); if (app.getUid() == Process.BLUETOOTH_UID) { app.setSystemComponent(true); systemBatteryConsumerBuilder.addUidBatteryConsumer(app); } } - final BatteryStats.ControllerActivityCounter counter = + final BatteryStats.ControllerActivityCounter activityCounter = batteryStats.getBluetoothControllerActivity(); - - calculatePowerAndDuration(counter, mSystemPowerAndDuration); + final long systemDurationMs = calculateDuration(activityCounter); + final double systemPowerMah = calculatePower(activityCounter); // Subtract what the apps used, but clamp to 0. - final long systemComponentDurationMs = Math.max(0, - mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs); - final double systemComponentPowerMah = Math.max(0, - mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah); - + final long systemComponentDurationMs = Math.max(0, systemDurationMs - total.durationMs); + final double systemComponentPowerMah = Math.max(0, systemPowerMah - total.powerMah); + if (DEBUG && systemComponentPowerMah != 0) { + Log.d(TAG, "Bluetooth active: time=" + (systemComponentDurationMs) + + " power=" + formatCharge(systemComponentPowerMah)); + } systemBatteryConsumerBuilder .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, systemComponentDurationMs) @@ -97,17 +92,17 @@ public class BluetoothPowerCalculator extends PowerCalculator { systemComponentPowerMah); } - private void calculateApp(UidBatteryConsumer.Builder app) { - calculatePowerAndDuration(app.getBatteryStatsUid().getBluetoothControllerActivity(), - mUidPowerAndDuration); + private void calculateApp(UidBatteryConsumer.Builder app, PowerAndDuration total) { + final BatteryStats.ControllerActivityCounter activityCounter = + app.getBatteryStatsUid().getBluetoothControllerActivity(); + final long durationMs = calculateDuration(activityCounter); + final double powerMah = calculatePower(activityCounter); - app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, - mUidPowerAndDuration.durationMs) - .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, - mUidPowerAndDuration.powerMah); + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_BLUETOOTH, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_BLUETOOTH, powerMah); - mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah; - mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs; + total.durationMs += durationMs; + total.powerMah += powerMah; } @Override @@ -117,20 +112,24 @@ public class BluetoothPowerCalculator extends PowerCalculator { return; } - mTotalPowerAndDuration.durationMs = 0; - mTotalPowerAndDuration.powerMah = 0; + PowerAndDuration total = new PowerAndDuration(); - super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers); + for (int i = sippers.size() - 1; i >= 0; i--) { + final BatterySipper app = sippers.get(i); + if (app.drainType == BatterySipper.DrainType.APP) { + calculateApp(app, app.uidObj, statsType, total); + } + } BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0); - calculatePowerAndDuration(batteryStats.getBluetoothControllerActivity(), - mSystemPowerAndDuration); + final BatteryStats.ControllerActivityCounter activityCounter = + batteryStats.getBluetoothControllerActivity(); + final double systemPowerMah = calculatePower(activityCounter); + final long systemDurationMs = calculateDuration(activityCounter); // Subtract what the apps used, but clamp to 0. - double powerMah = - Math.max(0, mSystemPowerAndDuration.powerMah - mTotalPowerAndDuration.powerMah); - final long durationMs = - Math.max(0, mSystemPowerAndDuration.durationMs - mTotalPowerAndDuration.durationMs); + final double powerMah = Math.max(0, systemPowerMah - total.powerMah); + final long durationMs = Math.max(0, systemDurationMs - total.durationMs); if (DEBUG && powerMah != 0) { Log.d(TAG, "Bluetooth active: time=" + (durationMs) + " power=" + formatCharge(powerMah)); @@ -152,27 +151,43 @@ public class BluetoothPowerCalculator extends PowerCalculator { } } - @Override - protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { + private void calculateApp(BatterySipper app, BatteryStats.Uid u, int statsType, + PowerAndDuration total) { + final BatteryStats.ControllerActivityCounter activityCounter = + u.getBluetoothControllerActivity(); + final long durationMs = calculateDuration(activityCounter); + final double powerMah = calculatePower(activityCounter); - calculatePowerAndDuration(u.getBluetoothControllerActivity(), mUidPowerAndDuration); - - app.bluetoothPowerMah = mUidPowerAndDuration.powerMah; - app.bluetoothRunningTimeMs = mUidPowerAndDuration.durationMs; + app.bluetoothRunningTimeMs = durationMs; + app.bluetoothPowerMah = powerMah; app.btRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA, statsType); app.btTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA, statsType); - mTotalPowerAndDuration.powerMah += mUidPowerAndDuration.powerMah; - mTotalPowerAndDuration.durationMs += mUidPowerAndDuration.durationMs; + total.durationMs += durationMs; + total.powerMah += powerMah; } - private void calculatePowerAndDuration(BatteryStats.ControllerActivityCounter counter, - PowerAndDuration powerAndDuration) { + private long calculateDuration(BatteryStats.ControllerActivityCounter counter) { if (counter == null) { - powerAndDuration.durationMs = 0; - powerAndDuration.powerMah = 0; - return; + return 0; + } + + return counter.getIdleTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED) + + counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED) + + counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED); + } + + private double calculatePower(BatteryStats.ControllerActivityCounter counter) { + if (counter == null) { + return 0; + } + + final double powerMah = + counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED) + / (double) (1000 * 60 * 60); + + if (powerMah != 0) { + return powerMah; } final long idleTimeMs = @@ -181,17 +196,7 @@ public class BluetoothPowerCalculator extends PowerCalculator { counter.getRxTimeCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED); final long txTimeMs = counter.getTxTimeCounters()[0].getCountLocked(BatteryStats.STATS_SINCE_CHARGED); - final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs; - double powerMah = - counter.getPowerCounter().getCountLocked(BatteryStats.STATS_SINCE_CHARGED) - / (double) (1000 * 60 * 60); - - if (powerMah == 0) { - powerMah = ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa)) - / (1000 * 60 * 60); - } - - powerAndDuration.durationMs = totalTimeMs; - powerAndDuration.powerMah = powerMah; + return ((idleTimeMs * mIdleMa) + (rxTimeMs * mRxMa) + (txTimeMs * mTxMa)) + / (1000 * 60 * 60); } } diff --git a/core/java/com/android/internal/os/CameraPowerCalculator.java b/core/java/com/android/internal/os/CameraPowerCalculator.java index 0365d9e9d600..6f8e9271d198 100644 --- a/core/java/com/android/internal/os/CameraPowerCalculator.java +++ b/core/java/com/android/internal/os/CameraPowerCalculator.java @@ -15,7 +15,10 @@ */ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; /** * Power calculator for the camera subsystem, excluding the flashlight. @@ -23,26 +26,33 @@ import android.os.BatteryStats; * Note: Power draw for the flash unit should be included in the FlashlightPowerCalculator. */ public class CameraPowerCalculator extends PowerCalculator { - private final double mCameraPowerOnAvg; + // Calculate camera power usage. Right now, this is a (very) rough estimate based on the + // average power usage for a typical camera application. + private final UsageBasedPowerEstimator mPowerEstimator; public CameraPowerCalculator(PowerProfile profile) { - mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA); + mPowerEstimator = new UsageBasedPowerEstimator( + profile.getAveragePower(PowerProfile.POWER_CAMERA)); } @Override - protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { + protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long durationMs = + mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA, powerMah); + } - // Calculate camera power usage. Right now, this is a (very) rough estimate based on the - // average power usage for a typical camera application. - final BatteryStats.Timer timer = u.getCameraTurnedOnTimer(); - if (timer != null) { - final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; - app.cameraTimeMs = totalTime; - app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60); - } else { - app.cameraTimeMs = 0; - app.cameraPowerMah = 0; - } + @Override + protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + final long durationMs = mPowerEstimator.calculateDuration(u.getCameraTurnedOnTimer(), + rawRealtimeUs, statsType); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.cameraTimeMs = durationMs; + app.cameraPowerMah = powerMah; } } diff --git a/core/java/com/android/internal/os/FlashlightPowerCalculator.java b/core/java/com/android/internal/os/FlashlightPowerCalculator.java index 330feef8f117..6c29a91f081f 100644 --- a/core/java/com/android/internal/os/FlashlightPowerCalculator.java +++ b/core/java/com/android/internal/os/FlashlightPowerCalculator.java @@ -15,32 +15,41 @@ */ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; /** * Power calculator for the flashlight. */ public class FlashlightPowerCalculator extends PowerCalculator { - private final double mFlashlightPowerOnAvg; + // Calculate flashlight power usage. Right now, this is based on the average power draw + // of the flash unit when kept on over a short period of time. + private final UsageBasedPowerEstimator mPowerEstimator; public FlashlightPowerCalculator(PowerProfile profile) { - mFlashlightPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT); + mPowerEstimator = new UsageBasedPowerEstimator( + profile.getAveragePower(PowerProfile.POWER_FLASHLIGHT)); } @Override - protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, - long rawUptimeUs, int statsType) { + protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(), + rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT, powerMah); + } - // Calculate flashlight power usage. Right now, this is based on the average power draw - // of the flash unit when kept on over a short period of time. - final BatteryStats.Timer timer = u.getFlashlightTurnedOnTimer(); - if (timer != null) { - final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; - app.flashlightTimeMs = totalTime; - app.flashlightPowerMah = (totalTime * mFlashlightPowerOnAvg) / (1000*60*60); - } else { - app.flashlightTimeMs = 0; - app.flashlightPowerMah = 0; - } + @Override + protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, + long rawUptimeUs, int statsType) { + final long durationMs = mPowerEstimator.calculateDuration(u.getFlashlightTurnedOnTimer(), + rawRealtimeUs, statsType); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.flashlightTimeMs = durationMs; + app.flashlightPowerMah = powerMah; } } diff --git a/core/java/com/android/internal/os/IdlePowerCalculator.java b/core/java/com/android/internal/os/IdlePowerCalculator.java index 44ad34417a4c..dcc8a15b2f50 100644 --- a/core/java/com/android/internal/os/IdlePowerCalculator.java +++ b/core/java/com/android/internal/os/IdlePowerCalculator.java @@ -16,7 +16,11 @@ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.SystemBatteryConsumer; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -29,46 +33,70 @@ import java.util.List; public class IdlePowerCalculator extends PowerCalculator { private static final String TAG = "IdlePowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final PowerProfile mPowerProfile; + private final double mAveragePowerCpuSuspendMahPerUs; + private final double mAveragePowerCpuIdleMahPerUs; + public long mDurationMs; + public double mPowerMah; public IdlePowerCalculator(PowerProfile powerProfile) { - mPowerProfile = powerProfile; + mAveragePowerCpuSuspendMahPerUs = + powerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND) + / (60 * 60 * 1_000_000.0); + mAveragePowerCpuIdleMahPerUs = + powerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE) + / (60 * 60 * 1_000_000.0); + } + + @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray<UserHandle> asUsers) { + calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs, + BatteryStats.STATS_SINCE_CHARGED); + if (mPowerMah != 0) { + builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_IDLE) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, mPowerMah) + .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, mDurationMs); + } + } + + @Override + public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { + calculatePowerAndDuration(batteryStats, rawRealtimeUs, rawUptimeUs, statsType); + + if (mPowerMah != 0) { + BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0); + bs.usagePowerMah = mPowerMah; + bs.usageTimeMs = mDurationMs; + bs.sumPower(); + sippers.add(bs); + } } /** - * Calculate the baseline power usage for the device when it is in suspend and idle. + * Calculates the baseline power usage for the device when it is in suspend and idle. * The device is drawing POWER_CPU_SUSPEND power at its lowest power state. * The device is drawing POWER_CPU_SUSPEND + POWER_CPU_IDLE power when a wakelock is held. */ - @Override - public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, - long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - long batteryUptimeUs = batteryStats.computeBatteryUptime(rawUptimeUs, statsType); + private void calculatePowerAndDuration(BatteryStats batteryStats, long rawRealtimeUs, + long rawUptimeUs, int statsType) { long batteryRealtimeUs = batteryStats.computeBatteryRealtime(rawRealtimeUs, statsType); - + long batteryUptimeUs = batteryStats.computeBatteryUptime(rawUptimeUs, statsType); if (DEBUG) { Log.d(TAG, "Battery type time: realtime=" + (batteryRealtimeUs / 1000) + " uptime=" + (batteryUptimeUs / 1000)); } - final double suspendPowerMaMs = (batteryRealtimeUs / 1000) - * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_SUSPEND); - final double idlePowerMaMs = (batteryUptimeUs / 1000) - * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE); - final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000); - if (DEBUG && totalPowerMah != 0) { + final double suspendPowerMah = batteryRealtimeUs * mAveragePowerCpuSuspendMahPerUs; + final double idlePowerMah = batteryUptimeUs * mAveragePowerCpuIdleMahPerUs; + mPowerMah = suspendPowerMah + idlePowerMah; + if (DEBUG && mPowerMah != 0) { Log.d(TAG, "Suspend: time=" + (batteryRealtimeUs / 1000) - + " power=" + formatCharge(suspendPowerMaMs / (60 * 60 * 1000))); + + " power=" + formatCharge(suspendPowerMah)); Log.d(TAG, "Idle: time=" + (batteryUptimeUs / 1000) - + " power=" + formatCharge(idlePowerMaMs / (60 * 60 * 1000))); - } - - if (totalPowerMah != 0) { - BatterySipper bs = new BatterySipper(BatterySipper.DrainType.IDLE, null, 0); - bs.usagePowerMah = totalPowerMah; - bs.usageTimeMs = batteryRealtimeUs / 1000; - bs.sumPower(); - sippers.add(bs); + + " power=" + formatCharge(idlePowerMah)); } + mDurationMs = batteryRealtimeUs / 1000; } } diff --git a/core/java/com/android/internal/os/MemoryPowerCalculator.java b/core/java/com/android/internal/os/MemoryPowerCalculator.java index 10d9b6519992..df4605838b28 100644 --- a/core/java/com/android/internal/os/MemoryPowerCalculator.java +++ b/core/java/com/android/internal/os/MemoryPowerCalculator.java @@ -1,64 +1,75 @@ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.SystemBatteryConsumer; import android.os.UserHandle; -import android.util.Log; import android.util.LongSparseArray; import android.util.SparseArray; import java.util.List; public class MemoryPowerCalculator extends PowerCalculator { - public static final String TAG = "MemoryPowerCalculator"; - private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final double[] powerAverages; + private final UsageBasedPowerEstimator[] mPowerEstimators; public MemoryPowerCalculator(PowerProfile profile) { int numBuckets = profile.getNumElements(PowerProfile.POWER_MEMORY); - powerAverages = new double[numBuckets]; + mPowerEstimators = new UsageBasedPowerEstimator[numBuckets]; for (int i = 0; i < numBuckets; i++) { - powerAverages[i] = profile.getAveragePower(PowerProfile.POWER_MEMORY, i); - if (powerAverages[i] == 0 && DEBUG) { - Log.d(TAG, "Problem with PowerProfile. Received 0 value in MemoryPowerCalculator"); - } + mPowerEstimators[i] = new UsageBasedPowerEstimator( + profile.getAveragePower(PowerProfile.POWER_MEMORY, i)); } } @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray<UserHandle> asUsers) { + final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = calculatePower(batteryStats, rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED); + builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_MEMORY) + .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); + } + + @Override public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { + final long durationMs = calculateDuration(batteryStats, rawRealtimeUs, statsType); + final double powerMah = calculatePower(batteryStats, rawRealtimeUs, statsType); BatterySipper memory = new BatterySipper(BatterySipper.DrainType.MEMORY, null, 0); - calculateRemaining(memory, batteryStats, rawRealtimeUs, rawUptimeUs, statsType); + memory.usageTimeMs = durationMs; + memory.usagePowerMah = powerMah; memory.sumPower(); if (memory.totalPowerMah > 0) { sippers.add(memory); } } - private void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs, - long rawUptimeUs, int statsType) { - double totalMah = 0; - long totalTimeMs = 0; - LongSparseArray<? extends BatteryStats.Timer> timers = stats.getKernelMemoryStats(); - for (int i = 0; i < timers.size() && i < powerAverages.length; i++) { - double mAatRail = powerAverages[(int) timers.keyAt(i)]; - long timeMs = timers.valueAt(i).getTotalTimeLocked(rawRealtimeUs, statsType); - double mAm = (mAatRail * timeMs) / (1000*60); - if(DEBUG) { - Log.d(TAG, "Calculating mAh for bucket " + timers.keyAt(i) + " while unplugged"); - Log.d(TAG, "Converted power profile number from " - + powerAverages[(int) timers.keyAt(i)] + " into " + mAatRail); - Log.d(TAG, "Calculated mAm " + mAm); - } - totalMah += mAm/60; - totalTimeMs += timeMs; + private long calculateDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { + long usageDurationMs = 0; + LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats(); + for (int i = 0; i < timers.size() && i < mPowerEstimators.length; i++) { + usageDurationMs += mPowerEstimators[i].calculateDuration(timers.valueAt(i), + rawRealtimeUs, statsType); } - app.usagePowerMah = totalMah; - app.usageTimeMs = totalTimeMs; - if (DEBUG) { - Log.d(TAG, String.format("Calculated total mAh for memory %f while unplugged %d ", - totalMah, totalTimeMs)); + return usageDurationMs; + } + + private double calculatePower(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { + double powerMah = 0; + LongSparseArray<? extends BatteryStats.Timer> timers = batteryStats.getKernelMemoryStats(); + for (int i = 0; i < timers.size() && i < mPowerEstimators.length; i++) { + UsageBasedPowerEstimator estimator = mPowerEstimators[(int) timers.keyAt(i)]; + final long usageDurationMs = + estimator.calculateDuration(timers.valueAt(i), rawRealtimeUs, statsType); + powerMah += estimator.calculatePower(usageDurationMs); } + return powerMah; } } diff --git a/core/java/com/android/internal/os/PhonePowerCalculator.java b/core/java/com/android/internal/os/PhonePowerCalculator.java index 992c487a9a66..6ab8c90d21d9 100644 --- a/core/java/com/android/internal/os/PhonePowerCalculator.java +++ b/core/java/com/android/internal/os/PhonePowerCalculator.java @@ -30,20 +30,20 @@ import java.util.List; * Estimates power consumed by telephony. */ public class PhonePowerCalculator extends PowerCalculator { - private final PowerProfile mPowerProfile; + private final UsageBasedPowerEstimator mPowerEstimator; public PhonePowerCalculator(PowerProfile powerProfile) { - mPowerProfile = powerProfile; + mPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)); } @Override public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, SparseArray<UserHandle> asUsers) { - long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, + final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000; - double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) - * phoneOnTimeMs / (60 * 60 * 1000); + final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); if (phoneOnPower != 0) { builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_PHONE) .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, phoneOnPower) @@ -54,9 +54,8 @@ public class PhonePowerCalculator extends PowerCalculator { @Override public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000; - double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) - * phoneOnTimeMs / (60 * 60 * 1000); + final long phoneOnTimeMs = batteryStats.getPhoneOnTime(rawRealtimeUs, statsType) / 1000; + final double phoneOnPower = mPowerEstimator.calculatePower(phoneOnTimeMs); if (phoneOnPower != 0) { BatterySipper bs = new BatterySipper(BatterySipper.DrainType.PHONE, null, 0); bs.usagePowerMah = phoneOnPower; diff --git a/core/java/com/android/internal/os/ScreenPowerCalculator.java b/core/java/com/android/internal/os/ScreenPowerCalculator.java index 09fb75bc2d2d..25f6b4d16971 100644 --- a/core/java/com/android/internal/os/ScreenPowerCalculator.java +++ b/core/java/com/android/internal/os/ScreenPowerCalculator.java @@ -16,7 +16,11 @@ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.SystemBatteryConsumer; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -30,10 +34,29 @@ public class ScreenPowerCalculator extends PowerCalculator { private static final String TAG = "ScreenPowerCalculator"; private static final boolean DEBUG = BatteryStatsHelper.DEBUG; - private final PowerProfile mPowerProfile; + private final UsageBasedPowerEstimator mScreenOnPowerEstimator; + private final UsageBasedPowerEstimator mScreenFullPowerEstimator; public ScreenPowerCalculator(PowerProfile powerProfile) { - mPowerProfile = powerProfile; + mScreenOnPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON)); + mScreenFullPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL)); + } + + @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray<UserHandle> asUsers) { + final long durationMs = computeDuration(batteryStats, rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = computePower(batteryStats, rawRealtimeUs, + BatteryStats.STATS_SINCE_CHARGED, durationMs); + if (powerMah != 0) { + builder.getOrCreateSystemBatteryConsumerBuilder(SystemBatteryConsumer.DRAIN_TYPE_SCREEN) + .setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE, powerMah); + } } /** @@ -42,30 +65,35 @@ public class ScreenPowerCalculator extends PowerCalculator { @Override public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - double power = 0; - final long screenOnTimeMs = batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000; - power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON); - final double screenFullPower = - mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL); + final long durationMs = computeDuration(batteryStats, rawRealtimeUs, statsType); + final double powerMah = computePower(batteryStats, rawRealtimeUs, statsType, durationMs); + if (powerMah != 0) { + final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0); + bs.usagePowerMah = powerMah; + bs.usageTimeMs = durationMs; + bs.sumPower(); + sippers.add(bs); + } + } + + private long computeDuration(BatteryStats batteryStats, long rawRealtimeUs, int statsType) { + return batteryStats.getScreenOnTime(rawRealtimeUs, statsType) / 1000; + } + + private double computePower(BatteryStats batteryStats, long rawRealtimeUs, int statsType, + long durationMs) { + double power = mScreenOnPowerEstimator.calculatePower(durationMs); for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) { - final double screenBinPower = screenFullPower * (i + 0.5f) - / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; final long brightnessTime = batteryStats.getScreenBrightnessTime(i, rawRealtimeUs, statsType) / 1000; - final double p = screenBinPower * brightnessTime; - if (DEBUG && p != 0) { + final double binPowerMah = mScreenFullPowerEstimator.calculatePower(brightnessTime) + * (i + 0.5f) / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; + if (DEBUG && binPowerMah != 0) { Log.d(TAG, "Screen bin #" + i + ": time=" + brightnessTime - + " power=" + formatCharge(p / (60 * 60 * 1000))); + + " power=" + formatCharge(binPowerMah)); } - power += p; - } - power /= (60 * 60 * 1000); // To hours - if (power != 0) { - final BatterySipper bs = new BatterySipper(BatterySipper.DrainType.SCREEN, null, 0); - bs.usagePowerMah = power; - bs.usageTimeMs = screenOnTimeMs; - bs.sumPower(); - sippers.add(bs); + power += binPowerMah; } + return power; } } diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java index b15dff67b619..55fc1bb607a9 100644 --- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java +++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java @@ -16,7 +16,11 @@ package com.android.internal.os; +import android.os.BatteryConsumer; import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; @@ -46,28 +50,35 @@ public class SystemServicePowerCalculator extends PowerCalculator { } @Override + public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query, + SparseArray<UserHandle> asUsers) { + calculateSystemServicePower(batteryStats); + super.calculate(builder, batteryStats, rawRealtimeUs, rawUptimeUs, query, asUsers); + } + + @Override + protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, + calculateSystemServerCpuPowerMah(u)); + } + + @Override public void calculate(List<BatterySipper> sippers, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, int statsType, SparseArray<UserHandle> asUsers) { - updateSystemServicePower(batteryStats); + calculateSystemServicePower(batteryStats); super.calculate(sippers, batteryStats, rawRealtimeUs, rawUptimeUs, statsType, asUsers); } @Override protected void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs, long rawUptimeUs, int statsType) { - final double proportionalUsage = u.getProportionalSystemServiceUsage(); - if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) { - double cpuPowerMaUs = 0; - for (int i = 0; i < mSystemServicePowerMaUs.length; i++) { - cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage; - } - - app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR; - } + app.systemServiceCpuPowerMah = calculateSystemServerCpuPowerMah(u); } - private void updateSystemServicePower(BatteryStats batteryStats) { + private void calculateSystemServicePower(BatteryStats batteryStats) { final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds(); if (systemServiceTimeAtCpuSpeeds == null) { return; @@ -94,6 +105,17 @@ public class SystemServicePowerCalculator extends PowerCalculator { } } + private double calculateSystemServerCpuPowerMah(BatteryStats.Uid u) { + double cpuPowerMaUs = 0; + final double proportionalUsage = u.getProportionalSystemServiceUsage(); + if (proportionalUsage > 0 && mSystemServicePowerMaUs != null) { + for (int i = 0; i < mSystemServicePowerMaUs.length; i++) { + cpuPowerMaUs += mSystemServicePowerMaUs[i] * proportionalUsage; + } + } + return cpuPowerMaUs / MICROSEC_IN_HR; + } + @Override public void reset() { mSystemServicePowerMaUs = null; diff --git a/core/java/com/android/internal/os/UsageBasedPowerEstimator.java b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java new file mode 100644 index 000000000000..5910b61f0f6f --- /dev/null +++ b/core/java/com/android/internal/os/UsageBasedPowerEstimator.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.os.BatteryStats; + +/** + * Implements a simple linear power model based on the assumption that the power consumer + * consumes a fixed current when it is used and no current when it is unused. + * + * <code>power = usageDuration * averagePower</code> + */ +public class UsageBasedPowerEstimator { + private static final double MILLIS_IN_HOUR = 1000.0 * 60 * 60; + private final double mAveragePowerMahPerMs; + + public UsageBasedPowerEstimator(double averagePowerMilliAmp) { + mAveragePowerMahPerMs = averagePowerMilliAmp / MILLIS_IN_HOUR; + } + + /** + * Given a {@link BatteryStats.Timer}, returns the accumulated duration. + */ + public long calculateDuration(BatteryStats.Timer timer, long rawRealtimeUs, int statsType) { + return timer == null ? 0 : timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000; + } + + /** + * Given a duration in milliseconds, return the estimated power consumption. + */ + public double calculatePower(long durationMs) { + return mAveragePowerMahPerMs * durationMs; + } +} diff --git a/core/java/com/android/internal/os/VideoPowerCalculator.java b/core/java/com/android/internal/os/VideoPowerCalculator.java new file mode 100644 index 000000000000..5d6caf578475 --- /dev/null +++ b/core/java/com/android/internal/os/VideoPowerCalculator.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.os; + +import android.os.BatteryConsumer; +import android.os.BatteryStats; +import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; + +/** + * A {@link PowerCalculator} to calculate power consumed by video hardware. + * + * Also see {@link PowerProfile#POWER_VIDEO}. + */ +public class VideoPowerCalculator extends PowerCalculator { + private final UsageBasedPowerEstimator mPowerEstimator; + + public VideoPowerCalculator(PowerProfile powerProfile) { + mPowerEstimator = new UsageBasedPowerEstimator( + powerProfile.getAveragePower(PowerProfile.POWER_VIDEO)); + } + + @Override + protected void calculateApp(UidBatteryConsumer.Builder app, BatteryStats.Uid u, + long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { + final long durationMs = mPowerEstimator.calculateDuration(u.getVideoTurnedOnTimer(), + rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED); + final double powerMah = mPowerEstimator.calculatePower(durationMs); + app.setUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO, durationMs) + .setConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO, powerMah); + } +} diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index efede2181628..3156f71fa113 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -843,7 +843,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, PrepareDir(user_source, 0710, user_id ? AID_ROOT : AID_SHELL, multiuser_get_uid(user_id, AID_EVERYBODY), fail_fn); - bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, true); + bool isAppDataIsolationEnabled = GetBoolProperty(kVoldAppDataIsolation, false); if (mount_mode == MOUNT_EXTERNAL_PASS_THROUGH) { const std::string pass_through_source = StringPrintf("/mnt/pass_through/%d", user_id); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 30535185bdae..ce3ed9dc8ba6 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2676,11 +2676,11 @@ The app can check whether it has this authorization by calling {@link android.provider.Settings#canDrawOverlays Settings.canDrawOverlays()}. - <p>Protection level: signature|preinstalled|appop|pre23|development --> + <p>Protection level: signature|appop|installer|pre23|development --> <permission android:name="android.permission.SYSTEM_ALERT_WINDOW" android:label="@string/permlab_systemAlertWindow" android:description="@string/permdesc_systemAlertWindow" - android:protectionLevel="signature|preinstalled|appop|pre23|development" /> + android:protectionLevel="signature|appop|installer|pre23|development" /> <!-- @deprecated Use {@link android.Manifest.permission#REQUEST_COMPANION_RUN_IN_BACKGROUND} @hide @@ -3591,6 +3591,14 @@ <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE" android:protectionLevel="signature" /> + <!-- Must be required by a android.service.translation.TranslationService, + to ensure that only the system can bind to it. + @SystemApi @hide This is not a third-party API (intended for OEMs and system apps). + <p>Protection level: signature + --> + <permission android:name="android.permission.BIND_TRANSLATION_SERVICE" + android:protectionLevel="signature" /> + <!-- Must be required by a android.service.contentsuggestions.ContentSuggestionsService, to ensure that only the system can bind to it. @SystemApi @hide This is not a third-party API (intended for OEMs and system apps). diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 7ca3fafdca47..ef54db1a422c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8292,6 +8292,23 @@ </declare-styleable> <!-- =============================== --> + <!-- Translation attributes --> + <!-- =============================== --> + <eat-comment /> + + <!-- Use <code>translation-service</code> as the root tag of the XML resource that describes + a {@link android.service.translation.TranslationService}, which is referenced from + its {@link android.service.translation.TranslationService#SERVICE_META_DATA} meta-data + entry. + @hide @SystemApi + --> + <declare-styleable name="TranslationService"> + <!-- Fully qualified class name of an activity that allows the user to modify + the settings for this service. --> + <attr name="settingsActivity" /> + </declare-styleable> + + <!-- =============================== --> <!-- Contacts meta-data attributes --> <!-- =============================== --> <eat-comment /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index da658cc3d525..cff1bdaa4477 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3724,6 +3724,14 @@ --> <string name="config_defaultAugmentedAutofillService" translatable="false"></string> + <!-- The package name for the system's translation service. + This service must be trusted, as it can be activated without explicit consent of the user. + If no service with the specified name exists on the device, translation wil be + disabled. + Example: "com.android.translation/.TranslationService" +--> + <string name="config_defaultTranslationService" translatable="false"></string> + <!-- The package name for the system's app prediction service. This service must be trusted, as it can be activated without explicit consent of the user. Example: "com.android.intelligence/.AppPredictionService" diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 31b4edd4e6e8..5b4294717e27 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3484,6 +3484,7 @@ <java-symbol type="string" name="config_defaultWellbeingPackage" /> <java-symbol type="string" name="config_defaultContentCaptureService" /> <java-symbol type="string" name="config_defaultAugmentedAutofillService" /> + <java-symbol type="string" name="config_defaultTranslationService" /> <java-symbol type="string" name="config_defaultAppPredictionService" /> <java-symbol type="string" name="config_defaultContentSuggestionsService" /> <java-symbol type="string" name="config_defaultSearchUiService" /> diff --git a/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java new file mode 100644 index 000000000000..e2a106484848 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/AmbientDisplayPowerCalculatorTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.SystemBatteryConsumer; +import android.view.Display; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AmbientDisplayPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_AMBIENT_DISPLAY, 360.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + + stats.noteScreenStateLocked(Display.STATE_ON, 1000, 1000, 1000); + stats.noteScreenStateLocked(Display.STATE_DOZE, 2000, 2000, 2000); + stats.noteScreenStateLocked(Display.STATE_OFF, 3000, 3000, 3000); + + AmbientDisplayPowerCalculator calculator = + new AmbientDisplayPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + SystemBatteryConsumer consumer = + mStatsRule.getSystemBatteryConsumer( + SystemBatteryConsumer.DRAIN_TYPE_AMBIENT_DISPLAY); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .isEqualTo(1000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) + .isWithin(PRECISION).of(0.1); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java new file mode 100644 index 000000000000..ed4638c1e7e0 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/AudioPowerCalculatorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.Process; +import android.os.UidBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class AudioPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_AUDIO, 360.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); + uidStats.noteAudioTurnedOnLocked(1000); + uidStats.noteAudioTurnedOffLocked(2000); + + AudioPowerCalculator calculator = + new AudioPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_AUDIO)) + .isEqualTo(1000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_AUDIO)) + .isWithin(PRECISION).of(0.1); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java index bd4154210cbf..8ff318e8d555 100644 --- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java +++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java @@ -21,6 +21,8 @@ import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ + AmbientDisplayPowerCalculatorTest.class, + AudioPowerCalculatorTest.class, BatteryStatsCpuTimesTest.class, BatteryStatsBackgroundStatsTest.class, BatteryStatsBinderCallStatsTest.class, @@ -42,6 +44,9 @@ import org.junit.runners.Suite; BatteryStatsUserLifecycleTests.class, BluetoothPowerCalculatorTest.class, BstatsCpuTimesValidationTest.class, + CameraPowerCalculatorTest.class, + FlashlightPowerCalculatorTest.class, + IdlePowerCalculatorTest.class, KernelCpuProcStringReaderTest.class, KernelCpuUidActiveTimeReaderTest.class, KernelCpuUidBpfMapReaderTest.class, @@ -55,6 +60,9 @@ import org.junit.runners.Suite; LongSamplingCounterArrayTest.class, PowerCalculatorTest.class, PowerProfileTest.class, + ScreenPowerCalculatorTest.class, + SystemServicePowerCalculatorTest.class, + VideoPowerCalculatorTest.class, com.android.internal.power.MeasuredEnergyStatsTest.class }) diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java new file mode 100644 index 000000000000..55f64f977933 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsRule.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; +import android.os.SystemBatteryConsumer; +import android.os.UidBatteryConsumer; +import android.util.SparseArray; + +import androidx.test.InstrumentationRegistry; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class BatteryUsageStatsRule implements TestRule { + private final PowerProfile mPowerProfile; + private final MockClocks mMockClocks = new MockClocks(); + private final MockBatteryStatsImpl mBatteryStats = new MockBatteryStatsImpl(mMockClocks) { + @Override + public boolean hasBluetoothActivityReporting() { + return true; + } + }; + + private BatteryUsageStats mBatteryUsageStats; + + public BatteryUsageStatsRule() { + Context context = InstrumentationRegistry.getContext(); + mPowerProfile = spy(new PowerProfile(context, true /* forTest */)); + mBatteryStats.setPowerProfile(mPowerProfile); + } + + public BatteryUsageStatsRule setAveragePower(String key, double value) { + when(mPowerProfile.getAveragePower(key)).thenReturn(value); + return this; + } + + public BatteryUsageStatsRule setAveragePower(String key, double[] values) { + when(mPowerProfile.getNumElements(key)).thenReturn(values.length); + for (int i = 0; i < values.length; i++) { + when(mPowerProfile.getAveragePower(key, i)).thenReturn(values[i]); + } + return this; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + noteOnBattery(); + base.evaluate(); + } + }; + } + + private void noteOnBattery() { + mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0); + } + + public PowerProfile getPowerProfile() { + return mPowerProfile; + } + + public MockBatteryStatsImpl getBatteryStats() { + return mBatteryStats; + } + + public BatteryStatsImpl.Uid getUidStats(int uid) { + return mBatteryStats.getUidStatsLocked(uid); + } + + public void setTime(long realtimeUs, long uptimeUs) { + mMockClocks.realtime = realtimeUs; + mMockClocks.uptime = uptimeUs; + } + + void apply(PowerCalculator calculator) { + BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false); + SparseArray<? extends BatteryStats.Uid> uidStats = mBatteryStats.getUidStats(); + for (int i = 0; i < uidStats.size(); i++) { + builder.getOrCreateUidBatteryConsumerBuilder(uidStats.valueAt(i)); + } + + calculator.calculate(builder, mBatteryStats, mMockClocks.realtime, mMockClocks.uptime, + BatteryUsageStatsQuery.DEFAULT, null); + + mBatteryUsageStats = builder.build(); + } + + public UidBatteryConsumer getUidBatteryConsumer(int uid) { + for (UidBatteryConsumer ubc : mBatteryUsageStats.getUidBatteryConsumers()) { + if (ubc.getUid() == uid) { + return ubc; + } + } + return null; + } + + public SystemBatteryConsumer getSystemBatteryConsumer( + @SystemBatteryConsumer.DrainType int drainType) { + for (SystemBatteryConsumer sbc : mBatteryUsageStats.getSystemBatteryConsumers()) { + if (sbc.getDrainType() == drainType) { + return sbc; + } + } + return null; + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java index 96eb8da71ddb..e5594712db10 100644 --- a/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BluetoothPowerCalculatorTest.java @@ -18,24 +18,17 @@ package com.android.internal.os; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.when; - import android.annotation.Nullable; import android.os.BatteryConsumer; -import android.os.BatteryUsageStats; -import android.os.BatteryUsageStatsQuery; import android.os.Process; import android.os.SystemBatteryConsumer; -import android.os.UidBatteryConsumer; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest @@ -43,83 +36,69 @@ public class BluetoothPowerCalculatorTest { private static final double PRECISION = 0.00001; private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; - @Mock - private PowerProfile mMockPowerProfile; - private MockBatteryStatsImpl mMockBatteryStats; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) { - @Override - public boolean hasBluetoothActivityReporting() { - return true; - } - }; - mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 100_000, 100_000); - when(mMockPowerProfile.getAveragePower( - PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE)).thenReturn(10.0); - when(mMockPowerProfile.getAveragePower( - PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX)).thenReturn(50.0); - when(mMockPowerProfile.getAveragePower( - PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX)).thenReturn(100.0); - } + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE, 10.0) + .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX, 50.0) + .setAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX, 100.0); @Test public void testTimerBasedModel() { - setDurationsAndPower( - mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID) + setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID) .getOrCreateBluetoothControllerActivityLocked(), 1000, 2000, 3000, 0); - setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID) + setDurationsAndPower(mStatsRule.getUidStats(APP_UID) .getOrCreateBluetoothControllerActivityLocked(), 4000, 5000, 6000, 0); setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl) - mMockBatteryStats.getBluetoothControllerActivity(), + mStatsRule.getBatteryStats().getBluetoothControllerActivity(), 6000, 8000, 10000, 0); - BatteryUsageStats batteryUsageStats = buildBatteryUsageStats(); + BluetoothPowerCalculator calculator = + new BluetoothPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); assertBluetoothPowerAndDuration( - getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID), + mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID), 0.11388, 6000); assertBluetoothPowerAndDuration( - getUidBatteryConsumer(batteryUsageStats, APP_UID), + mStatsRule.getUidBatteryConsumer(APP_UID), 0.24722, 15000); assertBluetoothPowerAndDuration( - getBluetoothSystemBatteryConsumer(batteryUsageStats, - SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), + mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), 0.15833, 9000); } @Test public void testReportedPowerBasedModel() { - setDurationsAndPower( - mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID) + setDurationsAndPower(mStatsRule.getUidStats(Process.BLUETOOTH_UID) .getOrCreateBluetoothControllerActivityLocked(), 1000, 2000, 3000, 360000); - setDurationsAndPower(mMockBatteryStats.getUidStatsLocked(APP_UID) + setDurationsAndPower(mStatsRule.getUidStats(APP_UID) .getOrCreateBluetoothControllerActivityLocked(), 4000, 5000, 6000, 720000); setDurationsAndPower((BatteryStatsImpl.ControllerActivityCounterImpl) - mMockBatteryStats.getBluetoothControllerActivity(), + mStatsRule.getBatteryStats().getBluetoothControllerActivity(), 6000, 8000, 10000, 1260000); - BatteryUsageStats batteryUsageStats = buildBatteryUsageStats(); + BluetoothPowerCalculator calculator = + new BluetoothPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); assertBluetoothPowerAndDuration( - getUidBatteryConsumer(batteryUsageStats, Process.BLUETOOTH_UID), + mStatsRule.getUidBatteryConsumer(Process.BLUETOOTH_UID), 0.1, 6000); assertBluetoothPowerAndDuration( - getUidBatteryConsumer(batteryUsageStats, APP_UID), + mStatsRule.getUidBatteryConsumer(APP_UID), 0.2, 15000); assertBluetoothPowerAndDuration( - getBluetoothSystemBatteryConsumer(batteryUsageStats, - SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), + mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_BLUETOOTH), 0.15, 9000); } @@ -132,38 +111,6 @@ public class BluetoothPowerCalculatorTest { controllerActivity.getPowerCounter().addCountLocked(powerMaMs); } - private BatteryUsageStats buildBatteryUsageStats() { - BatteryUsageStats.Builder builder = new BatteryUsageStats.Builder(0, 0, false); - builder.getOrCreateUidBatteryConsumerBuilder( - mMockBatteryStats.getUidStatsLocked(Process.BLUETOOTH_UID)); - builder.getOrCreateUidBatteryConsumerBuilder( - mMockBatteryStats.getUidStatsLocked(APP_UID)); - - BluetoothPowerCalculator bpc = new BluetoothPowerCalculator(mMockPowerProfile); - bpc.calculate(builder, mMockBatteryStats, 200_000, 200_000, BatteryUsageStatsQuery.DEFAULT, - null); - return builder.build(); - } - - private UidBatteryConsumer getUidBatteryConsumer(BatteryUsageStats batteryUsageStats, int uid) { - for (UidBatteryConsumer ubc : batteryUsageStats.getUidBatteryConsumers()) { - if (ubc.getUid() == uid) { - return ubc; - } - } - return null; - } - - private SystemBatteryConsumer getBluetoothSystemBatteryConsumer( - BatteryUsageStats batteryUsageStats, int drainType) { - for (SystemBatteryConsumer sbc : batteryUsageStats.getSystemBatteryConsumers()) { - if (sbc.getDrainType() == drainType) { - return sbc; - } - } - return null; - } - private void assertBluetoothPowerAndDuration(@Nullable BatteryConsumer batteryConsumer, double powerMah, int durationMs) { assertThat(batteryConsumer).isNotNull(); diff --git a/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java new file mode 100644 index 000000000000..a21dd58b0757 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/CameraPowerCalculatorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.Process; +import android.os.UidBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class CameraPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_CAMERA, 360.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); + uidStats.noteCameraTurnedOnLocked(1000); + uidStats.noteCameraTurnedOffLocked(2000); + + CameraPowerCalculator calculator = + new CameraPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_CAMERA)) + .isEqualTo(1000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_CAMERA)) + .isWithin(PRECISION).of(0.1); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java new file mode 100644 index 000000000000..b7bbedd9cdb7 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/FlashlightPowerCalculatorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.Process; +import android.os.UidBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class FlashlightPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); + uidStats.noteFlashlightTurnedOnLocked(1000); + uidStats.noteFlashlightTurnedOffLocked(2000); + + FlashlightPowerCalculator calculator = + new FlashlightPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_FLASHLIGHT)) + .isEqualTo(1000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_FLASHLIGHT)) + .isWithin(PRECISION).of(0.1); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java new file mode 100644 index 000000000000..781e72560279 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/IdlePowerCalculatorTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.SystemBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IdlePowerCalculatorTest { + private static final double PRECISION = 0.00001; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_CPU_IDLE, 720.0) + .setAveragePower(PowerProfile.POWER_CPU_SUSPEND, 360.0); + + @Test + public void testTimerBasedModel() { + mStatsRule.setTime(3_000_000, 2_000_000); + + IdlePowerCalculator calculator = new IdlePowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + SystemBatteryConsumer consumer = + mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_IDLE); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .isEqualTo(3000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) + .isWithin(PRECISION).of(0.7); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java new file mode 100644 index 000000000000..8f21503a6d77 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/MemoryPowerCalculatorTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.SystemBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MemoryPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_MEMORY, new double[] {360.0, 720.0, 1080.0}); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + + // First update establishes a baseline + stats.getKernelMemoryTimerLocked(0).update(0, 1, 0); + stats.getKernelMemoryTimerLocked(2).update(0, 1, 0); + + stats.getKernelMemoryTimerLocked(0).update(1000000, 1, 4000000); + stats.getKernelMemoryTimerLocked(2).update(2000000, 1, 8000000); + + MemoryPowerCalculator calculator = + new MemoryPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + SystemBatteryConsumer consumer = + mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_MEMORY); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .isEqualTo(3000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) + .isWithin(PRECISION).of(0.7); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java index c7751371d557..fc237219be51 100644 --- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java +++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java @@ -46,6 +46,10 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl { mOnBatteryTimeBase); mScreenDozeTimer = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null, mOnBatteryTimeBase); + for (int i = 0; i < mScreenBrightnessTimer.length; i++) { + mScreenBrightnessTimer[i] = new BatteryStatsImpl.StopwatchTimer(clocks, null, -1, null, + mOnBatteryTimeBase); + } mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase); mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, 1); setExternalStatsSyncLocked(new DummyExternalStatsSync()); diff --git a/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java new file mode 100644 index 000000000000..e43caa37f711 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/ScreenPowerCalculatorTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.SystemBatteryConsumer; +import android.view.Display; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class ScreenPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_SCREEN_ON, 360.0) + .setAveragePower(PowerProfile.POWER_SCREEN_FULL, 3600.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl stats = mStatsRule.getBatteryStats(); + + stats.noteScreenStateLocked(Display.STATE_ON, 1000, 1000, 1000); + stats.noteScreenBrightnessLocked(100, 1000, 1000); + stats.noteScreenBrightnessLocked(200, 2000, 2000); + stats.noteScreenStateLocked(Display.STATE_OFF, 3000, 3000, 3000); + + ScreenPowerCalculator calculator = + new ScreenPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + SystemBatteryConsumer consumer = + mStatsRule.getSystemBatteryConsumer(SystemBatteryConsumer.DRAIN_TYPE_SCREEN); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_USAGE)) + .isEqualTo(2000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_USAGE)) + .isWithin(PRECISION).of(1.2); + } +} diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java index dbb36fbd1650..a5cafb974b0e 100644 --- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java +++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java @@ -16,50 +16,46 @@ package com.android.internal.os; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; -import android.content.Context; -import android.os.BatteryStats; +import android.os.BatteryConsumer; import android.os.Binder; import android.os.Process; import androidx.annotation.Nullable; -import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; -import java.util.List; @SmallTest @RunWith(AndroidJUnit4.class) public class SystemServicePowerCalculatorTest { - private PowerProfile mProfile; + private static final double PRECISION = 0.0000001; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule(); + private MockBatteryStatsImpl mMockBatteryStats; private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader; private MockSystemServerCpuThreadReader mMockSystemServerCpuThreadReader; - private SystemServicePowerCalculator mSystemServicePowerCalculator; @Before public void setUp() throws IOException { - Context context = InstrumentationRegistry.getContext(); - mProfile = new PowerProfile(context, true /* forTest */); mMockSystemServerCpuThreadReader = new MockSystemServerCpuThreadReader(); mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader(); - mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks()) - .setPowerProfile(mProfile) + mMockBatteryStats = mStatsRule.getBatteryStats() .setSystemServerCpuThreadReader(mMockSystemServerCpuThreadReader) .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader) .setUserInfoProvider(new MockUserInfoProvider()); - mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0); - mSystemServicePowerCalculator = new SystemServicePowerCalculator(mProfile); } @Test @@ -103,15 +99,17 @@ public class SystemServicePowerCalculatorTest { mMockBatteryStats.updateSystemServiceCallStats(); mMockBatteryStats.updateSystemServerThreadStats(); - BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP, - mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0); - BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP, - mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0); - mSystemServicePowerCalculator.calculate(List.of(app1, app2), mMockBatteryStats, 0, 0, - BatteryStats.STATS_SINCE_CHARGED, null); + SystemServicePowerCalculator calculator = new SystemServicePowerCalculator( + mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); - assertEquals(0.00016269, app1.systemServiceCpuPowerMah, 0.0000001); - assertEquals(0.00146426, app2.systemServiceCpuPowerMah, 0.0000001); + assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid1) + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES)) + .isWithin(PRECISION).of(0.00016269); + assertThat(mStatsRule.getUidBatteryConsumer(workSourceUid2) + .getConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES)) + .isWithin(PRECISION).of(0.00146426); } private static class MockKernelCpuUidFreqTimeReader extends diff --git a/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java new file mode 100644 index 000000000000..39eac49400ec --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/VideoPowerCalculatorTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.BatteryConsumer; +import android.os.Process; +import android.os.UidBatteryConsumer; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VideoPowerCalculatorTest { + private static final double PRECISION = 0.00001; + + private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42; + + @Rule + public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule() + .setAveragePower(PowerProfile.POWER_VIDEO, 360.0); + + @Test + public void testTimerBasedModel() { + BatteryStatsImpl.Uid uidStats = mStatsRule.getUidStats(APP_UID); + uidStats.noteVideoTurnedOnLocked(1000); + uidStats.noteVideoTurnedOffLocked(2000); + + VideoPowerCalculator calculator = + new VideoPowerCalculator(mStatsRule.getPowerProfile()); + + mStatsRule.apply(calculator); + + UidBatteryConsumer consumer = mStatsRule.getUidBatteryConsumer(APP_UID); + assertThat(consumer.getUsageDurationMillis(BatteryConsumer.TIME_COMPONENT_VIDEO)) + .isEqualTo(1000); + assertThat(consumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_VIDEO)) + .isWithin(PRECISION).of(0.1); + } +} diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java index 6eefeb8f3f2a..e56bd5167906 100644 --- a/identity/java/android/security/identity/Util.java +++ b/identity/java/android/security/identity/Util.java @@ -16,6 +16,8 @@ package android.security.identity; +import android.annotation.NonNull; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidKeyException; @@ -28,7 +30,10 @@ import java.util.Collection; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; -class Util { +/** + * @hide + */ +public class Util { private static final String TAG = "Util"; static int[] integerCollectionToArray(Collection<Integer> collection) { @@ -91,8 +96,9 @@ class Util { * 255.DigestSize, where DigestSize is the size of the underlying HMAC. * @return size pseudorandom bytes. */ - static byte[] computeHkdf( - String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) { + @NonNull public static byte[] computeHkdf( + @NonNull String macAlgorithm, @NonNull final byte[] ikm, @NonNull final byte[] salt, + @NonNull final byte[] info, int size) { Mac mac = null; try { mac = Mac.getInstance(macAlgorithm); @@ -137,4 +143,5 @@ class Util { } } + private Util() {} } diff --git a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json index 4070829fcfbe..0290d9f4b316 100644 --- a/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json +++ b/libs/WindowManager/Shell/res/raw/wm_shell_protolog.json @@ -7,24 +7,12 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" }, - "-1534364071": { - "message": "onTransitionReady %s: %s", - "level": "VERBOSE", - "group": "WM_SHELL_TRANSITIONS", - "at": "com\/android\/wm\/shell\/Transitions.java" - }, "-1501874464": { "message": "Fullscreen Task Appeared: #%d", "level": "VERBOSE", "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/FullscreenTaskListener.java" }, - "-1480787369": { - "message": "Transition requested: type=%d %s", - "level": "VERBOSE", - "group": "WM_SHELL_TRANSITIONS", - "at": "com\/android\/wm\/shell\/Transitions.java" - }, "-1382704050": { "message": "Display removed: %d", "level": "VERBOSE", @@ -97,12 +85,6 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/apppairs\/AppPairsController.java" }, - "-191422040": { - "message": "Transition animations finished, notifying core %s", - "level": "VERBOSE", - "group": "WM_SHELL_TRANSITIONS", - "at": "com\/android\/wm\/shell\/Transitions.java" - }, "157713005": { "message": "Task info changed taskId=%d", "level": "VERBOSE", @@ -115,6 +97,12 @@ "group": "WM_SHELL_DRAG_AND_DROP", "at": "com\/android\/wm\/shell\/draganddrop\/DropOutlineDrawable.java" }, + "325110414": { + "message": "Transition animations finished, notifying core %s", + "level": "VERBOSE", + "group": "WM_SHELL_TRANSITIONS", + "at": "com\/android\/wm\/shell\/transition\/Transitions.java" + }, "375908576": { "message": "Clip description: handlingDrag=%b itemCount=%d mimeTypes=%s", "level": "VERBOSE", @@ -145,6 +133,12 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java" }, + "846958769": { + "message": "Transition requested: type=%d %s", + "level": "VERBOSE", + "group": "WM_SHELL_TRANSITIONS", + "at": "com\/android\/wm\/shell\/transition\/Transitions.java" + }, "900599280": { "message": "Can't pair unresizeable tasks task1.isResizeable=%b task1.isResizeable=%b", "level": "ERROR", @@ -169,6 +163,12 @@ "group": "WM_SHELL_TASK_ORG", "at": "com\/android\/wm\/shell\/legacysplitscreen\/LegacySplitScreenTaskListener.java" }, + "1070270131": { + "message": "onTransitionReady %s: %s", + "level": "VERBOSE", + "group": "WM_SHELL_TRANSITIONS", + "at": "com\/android\/wm\/shell\/transition\/Transitions.java" + }, "1079041527": { "message": "incrementPool size=%d", "level": "VERBOSE", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java index 8817f8aaec7c..0146b728bcad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java @@ -30,6 +30,7 @@ import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index 00567618ef06..0cee0a21bde3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -24,9 +24,9 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.annotations.ExternalThread; import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; -import java.util.concurrent.TimeUnit; /** * The entry point implementation into the shell for initializing shell internal state. @@ -41,6 +41,7 @@ public class ShellInitImpl { private final Optional<AppPairs> mAppPairsOptional; private final FullscreenTaskListener mFullscreenTaskListener; private final ShellExecutor mMainExecutor; + private final Transitions mTransitions; private final InitImpl mImpl = new InitImpl(); @@ -50,6 +51,7 @@ public class ShellInitImpl { Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<AppPairs> appPairsOptional, FullscreenTaskListener fullscreenTaskListener, + Transitions transitions, ShellExecutor mainExecutor) { return new ShellInitImpl(displayImeController, dragAndDropController, @@ -57,6 +59,7 @@ public class ShellInitImpl { legacySplitScreenOptional, appPairsOptional, fullscreenTaskListener, + transitions, mainExecutor).mImpl; } @@ -66,6 +69,7 @@ public class ShellInitImpl { Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<AppPairs> appPairsOptional, FullscreenTaskListener fullscreenTaskListener, + Transitions transitions, ShellExecutor mainExecutor) { mDisplayImeController = displayImeController; mDragAndDropController = dragAndDropController; @@ -73,6 +77,7 @@ public class ShellInitImpl { mLegacySplitScreenOptional = legacySplitScreenOptional; mAppPairsOptional = appPairsOptional; mFullscreenTaskListener = fullscreenTaskListener; + mTransitions = transitions; mMainExecutor = mainExecutor; } @@ -89,6 +94,10 @@ public class ShellInitImpl { // Bind the splitscreen impl to the drag drop controller mDragAndDropController.initialize(mLegacySplitScreenOptional); + + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + mTransitions.register(mShellTaskOrganizer); + } } @ExternalThread diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java index 9e1f0a2ed493..a785cffb3df0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java @@ -43,7 +43,6 @@ import android.window.WindowContainerTransaction; import com.android.internal.policy.DividerSnapAlgorithm; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.Transitions; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; @@ -54,6 +53,7 @@ import com.android.wm.shell.common.SystemWindows; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.TransactionPool; +import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.lang.ref.WeakReference; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java index 3ed070b40816..5a493c234ce3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java @@ -38,8 +38,8 @@ import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.Transitions; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java index 93520c0b59de..94b2cc0455bd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java @@ -38,9 +38,9 @@ import android.view.WindowManager; import android.window.TransitionInfo; import android.window.WindowContainerTransaction; -import com.android.wm.shell.Transitions; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ExternalThread; +import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java index 90a8de02deb8..ad05e6d3e6c4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java @@ -39,8 +39,8 @@ import android.window.WindowContainerTransaction; import android.window.WindowOrganizer; import com.android.internal.annotations.GuardedBy; -import com.android.wm.shell.Transitions; import com.android.wm.shell.common.SyncTransactionQueue; +import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.List; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java deleted file mode 100644 index ffa6c9921d97..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.wm.shell.pip.tv; - -import static android.app.ActivityTaskManager.INVALID_STACK_ID; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.content.Intent.ACTION_MEDIA_RESOURCE_GRANTED; - -import static com.android.wm.shell.pip.tv.PipNotification.ACTION_CLOSE; -import static com.android.wm.shell.pip.tv.PipNotification.ACTION_MENU; - -import android.app.ActivityManager; -import android.app.ActivityTaskManager; -import android.app.ActivityTaskManager.RootTaskInfo; -import android.app.IActivityTaskManager; -import android.app.RemoteAction; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ParceledListSlice; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.os.Handler; -import android.os.RemoteException; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; -import android.view.DisplayInfo; - -import com.android.wm.shell.R; -import com.android.wm.shell.WindowManagerShellWrapper; -import com.android.wm.shell.common.TaskStackListenerCallback; -import com.android.wm.shell.common.TaskStackListenerImpl; -import com.android.wm.shell.pip.PinnedStackListenerForwarder; -import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.pip.PipBoundsAlgorithm; -import com.android.wm.shell.pip.PipBoundsState; -import com.android.wm.shell.pip.PipMediaController; -import com.android.wm.shell.pip.PipTaskOrganizer; - -import java.util.Objects; - -/** - * Manages the picture-in-picture (PIP) UI and states. - */ -public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback, - TvPipMenuController.Delegate { - private static final String TAG = "TvPipController"; - static final boolean DEBUG = false; - - /** - * Unknown or invalid state - */ - public static final int STATE_UNKNOWN = -1; - /** - * State when there's no PIP. - */ - public static final int STATE_NO_PIP = 0; - /** - * State when PIP is shown. This is used as default PIP state. - */ - public static final int STATE_PIP = 1; - /** - * State when PIP menu dialog is shown. - */ - public static final int STATE_PIP_MENU = 2; - - private static final int TASK_ID_NO_PIP = -1; - private static final int INVALID_RESOURCE_TYPE = -1; - - private final Context mContext; - private final PipBoundsState mPipBoundsState; - private final PipBoundsAlgorithm mPipBoundsAlgorithm; - private final PipTaskOrganizer mPipTaskOrganizer; - private final PipMediaController mPipMediaController; - private final TvPipMenuController mTvPipMenuController; - private final PipNotification mPipNotification; - - private IActivityTaskManager mActivityTaskManager; - private int mState = STATE_NO_PIP; - private final Handler mHandler = new Handler(); - private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; - private int mPipTaskId = TASK_ID_NO_PIP; - private int mPinnedStackId = INVALID_STACK_ID; - private String[] mLastPackagesResourceGranted; - private ParceledListSlice<RemoteAction> mCustomActions; - private WindowManagerShellWrapper mWindowManagerShellWrapper; - private int mResizeAnimationDuration; - - // Used to calculate the movement bounds - private final DisplayInfo mTmpDisplayInfo = new DisplayInfo(); - private final Rect mTmpInsetBounds = new Rect(); - - // Keeps track of the IME visibility to adjust the PiP when the IME is visible - private boolean mImeVisible; - private int mImeHeightAdjustment; - - private final Runnable mClosePipRunnable = this::closePip; - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG) { - Log.d(TAG, "mBroadcastReceiver, action: " + intent.getAction()); - } - switch (intent.getAction()) { - case ACTION_MENU: - showPictureInPictureMenu(); - break; - case ACTION_CLOSE: - closePip(); - break; - case ACTION_MEDIA_RESOURCE_GRANTED: - String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); - int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, - INVALID_RESOURCE_TYPE); - if (packageNames != null && packageNames.length > 0 - && resourceType == Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC) { - handleMediaResourceGranted(packageNames); - } - break; - } - } - }; - - private final PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener = - new PipControllerPinnedStackListener(); - - @Override - public void registerSessionListenerForCurrentUser() { - mPipMediaController.registerSessionListenerForCurrentUser(); - } - - /** - * Handler for messages from the PIP controller. - */ - private class PipControllerPinnedStackListener extends - PinnedStackListenerForwarder.PinnedStackListener { - @Override - public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { - mPipBoundsState.setImeVisibility(imeVisible, imeHeight); - if (mState == STATE_PIP) { - if (mImeVisible != imeVisible) { - if (imeVisible) { - // Save the IME height adjustment, and offset to not occlude the IME - mPipBoundsState.getNormalBounds().offset(0, -imeHeight); - mImeHeightAdjustment = imeHeight; - } else { - // Apply the inverse adjustment when the IME is hidden - mPipBoundsState.getNormalBounds().offset(0, mImeHeightAdjustment); - } - mImeVisible = imeVisible; - resizePinnedStack(STATE_PIP); - } - } - } - - @Override - public void onMovementBoundsChanged(boolean fromImeAdjustment) { - mTmpDisplayInfo.copyFrom(mPipBoundsState.getDisplayInfo()); - mPipBoundsAlgorithm.getInsetBounds(mTmpInsetBounds); - } - - @Override - public void onActionsChanged(ParceledListSlice<RemoteAction> actions) { - mCustomActions = actions; - mTvPipMenuController.setAppActions(mCustomActions); - } - } - - public PipController(Context context, - PipBoundsState pipBoundsState, - PipBoundsAlgorithm pipBoundsAlgorithm, - PipTaskOrganizer pipTaskOrganizer, - TvPipMenuController tvPipMenuController, - PipMediaController pipMediaController, - PipNotification pipNotification, - TaskStackListenerImpl taskStackListener, - WindowManagerShellWrapper windowManagerShellWrapper) { - mContext = context; - mPipBoundsState = pipBoundsState; - mPipNotification = pipNotification; - mPipBoundsAlgorithm = pipBoundsAlgorithm; - mPipMediaController = pipMediaController; - mTvPipMenuController = tvPipMenuController; - mTvPipMenuController.setDelegate(this); - // Ensure that we have the display info in case we get calls to update the bounds - // before the listener calls back - final DisplayInfo displayInfo = new DisplayInfo(); - context.getDisplay().getDisplayInfo(displayInfo); - mPipBoundsState.setDisplayInfo(displayInfo); - - mResizeAnimationDuration = context.getResources() - .getInteger(R.integer.config_pipResizeAnimationDuration); - mPipTaskOrganizer = pipTaskOrganizer; - mPipTaskOrganizer.registerPipTransitionCallback(this); - mActivityTaskManager = ActivityTaskManager.getService(); - - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_CLOSE); - intentFilter.addAction(ACTION_MENU); - intentFilter.addAction(ACTION_MEDIA_RESOURCE_GRANTED); - mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL); - - // Initialize the last orientation and apply the current configuration - Configuration initialConfig = mContext.getResources().getConfiguration(); - mLastOrientation = initialConfig.orientation; - loadConfigurationsAndApply(initialConfig); - - mWindowManagerShellWrapper = windowManagerShellWrapper; - try { - mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); - } catch (RemoteException e) { - Log.e(TAG, "Failed to register pinned stack listener", e); - } - - // Handle for system task stack changes. - taskStackListener.addListener( - new TaskStackListenerCallback() { - @Override - public void onTaskStackChanged() { - PipController.this.onTaskStackChanged(); - } - - @Override - public void onActivityPinned(String packageName, int userId, int taskId, - int stackId) { - PipController.this.onActivityPinned(packageName); - } - - @Override - public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, - boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { - PipController.this.onActivityRestartAttempt(task, clearedTask); - } - }); - } - - private void loadConfigurationsAndApply(Configuration newConfig) { - if (mLastOrientation != newConfig.orientation) { - // Don't resize the pinned stack on orientation change. TV does not care about this case - // and this could clobber the existing animation to the new bounds calculated by WM. - mLastOrientation = newConfig.orientation; - return; - } - - final Rect menuBounds = Rect.unflattenFromString( - mContext.getResources().getString(R.string.pip_menu_bounds)); - mPipBoundsState.setExpandedBounds(menuBounds); - - resizePinnedStack(getPinnedTaskInfo() == null ? STATE_NO_PIP : STATE_PIP); - } - - /** - * Updates the PIP per configuration changed. - */ - @Override - public void onConfigurationChanged(Configuration newConfig) { - loadConfigurationsAndApply(newConfig); - mPipNotification.onConfigurationChanged(mContext); - } - - /** - * Shows the picture-in-picture menu if an activity is in picture-in-picture mode. - */ - public void showPictureInPictureMenu() { - if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), current state=" + getStateDescription()); - - if (getState() == STATE_PIP) { - resizePinnedStack(STATE_PIP_MENU); - } - } - - /** - * Closes PIP (PIPed activity and PIP system UI). - */ - @Override - public void closePip() { - if (DEBUG) Log.d(TAG, "closePip(), current state=" + getStateDescription()); - - closePipInternal(true); - } - - private void closePipInternal(boolean removePipStack) { - if (DEBUG) { - Log.d(TAG, - "closePipInternal() removePipStack=" + removePipStack + ", current state=" - + getStateDescription()); - } - - mState = STATE_NO_PIP; - mPipTaskId = TASK_ID_NO_PIP; - if (removePipStack) { - try { - mActivityTaskManager.removeTask(mPinnedStackId); - } catch (RemoteException e) { - Log.e(TAG, "removeTask failed", e); - } finally { - mPinnedStackId = INVALID_STACK_ID; - } - } - mPipNotification.dismiss(); - mTvPipMenuController.hideMenu(); - mHandler.removeCallbacks(mClosePipRunnable); - } - - @Override - public void movePipToNormalPosition() { - resizePinnedStack(PipController.STATE_PIP); - } - - /** - * Moves the PIPed activity to the fullscreen and closes PIP system UI. - */ - @Override - public void movePipToFullscreen() { - if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription()); - - mPipTaskId = TASK_ID_NO_PIP; - mTvPipMenuController.hideMenu(); - mPipNotification.dismiss(); - - resizePinnedStack(STATE_NO_PIP); - } - - private void onActivityPinned(String packageName) { - final RootTaskInfo taskInfo = getPinnedTaskInfo(); - if (DEBUG) Log.d(TAG, "onActivityPinned, task=" + taskInfo); - if (taskInfo == null) { - Log.w(TAG, "Cannot find pinned stack"); - return; - } - - // At this point PipBoundsState knows the correct aspect ratio for this pinned task, so we - // use PipBoundsAlgorithm to calculate the normal bounds for the task (PipBoundsAlgorithm - // will query PipBoundsState for the aspect ratio) and pass the bounds over to the - // PipBoundsState. - mPipBoundsState.setNormalBounds(mPipBoundsAlgorithm.getNormalBounds()); - - mPinnedStackId = taskInfo.taskId; - mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1]; - - // Set state to STATE_PIP so we show it when the pinned stack animation ends. - mState = STATE_PIP; - mPipMediaController.onActivityPinned(); - mPipNotification.show(packageName); - } - - private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, - boolean clearedTask) { - if (task.getWindowingMode() != WINDOWING_MODE_PINNED) { - return; - } - if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()"); - - // If PIPed activity is launched again by Launcher or intent, make it fullscreen. - movePipToFullscreen(); - } - - private void onTaskStackChanged() { - if (DEBUG) Log.d(TAG, "onTaskStackChanged()"); - - if (getState() != STATE_NO_PIP) { - boolean hasPip = false; - - RootTaskInfo taskInfo = getPinnedTaskInfo(); - if (taskInfo == null || taskInfo.childTaskIds == null) { - Log.w(TAG, "There is nothing in pinned stack"); - closePipInternal(false); - return; - } - for (int i = taskInfo.childTaskIds.length - 1; i >= 0; --i) { - if (taskInfo.childTaskIds[i] == mPipTaskId) { - // PIP task is still alive. - hasPip = true; - break; - } - } - if (!hasPip) { - // PIP task doesn't exist anymore in PINNED_STACK. - closePipInternal(true); - return; - } - } - if (getState() == STATE_PIP) { - if (!Objects.equals(mPipBoundsState.getBounds(), mPipBoundsState.getNormalBounds())) { - resizePinnedStack(STATE_PIP); - } - } - } - - /** - * Resize the Pip to the appropriate size for the input state. - * - * @param state In Pip state also used to determine the new size for the Pip. - */ - public void resizePinnedStack(int state) { - if (DEBUG) { - Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state=" - + getStateDescription(), new Exception()); - } - final boolean wasStateNoPip = (mState == STATE_NO_PIP); - mTvPipMenuController.hideMenu(); - mState = state; - final Rect newBounds; - switch (mState) { - case STATE_NO_PIP: - newBounds = null; - // If the state was already STATE_NO_PIP, then do not resize the stack below as it - // will not exist - if (wasStateNoPip) { - return; - } - break; - case STATE_PIP_MENU: - newBounds = mPipBoundsState.getExpandedBounds(); - break; - case STATE_PIP: // fallthrough - default: - newBounds = mPipBoundsState.getNormalBounds(); - break; - } - if (newBounds != null) { - mPipTaskOrganizer.scheduleAnimateResizePip(newBounds, mResizeAnimationDuration, null); - } else { - mPipTaskOrganizer.exitPip(mResizeAnimationDuration); - } - } - - /** - * @return the current state. - */ - private int getState() { - return mState; - } - - private void showPipMenu() { - if (DEBUG) Log.d(TAG, "showPipMenu(), current state=" + getStateDescription()); - - mState = STATE_PIP_MENU; - mTvPipMenuController.showMenu(); - } - - /** - * Returns {@code true} if PIP is shown. - */ - public boolean isPipShown() { - return mState != STATE_NO_PIP; - } - - private RootTaskInfo getPinnedTaskInfo() { - RootTaskInfo taskInfo = null; - try { - taskInfo = ActivityTaskManager.getService().getRootTaskInfo( - WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); - } catch (RemoteException e) { - Log.e(TAG, "getRootTaskInfo failed", e); - } - if (DEBUG) Log.d(TAG, "getPinnedTaskInfo(), taskInfo=" + taskInfo); - return taskInfo; - } - - private void handleMediaResourceGranted(String[] packageNames) { - if (getState() == STATE_NO_PIP) { - mLastPackagesResourceGranted = packageNames; - } else { - boolean requestedFromLastPackages = false; - if (mLastPackagesResourceGranted != null) { - for (String packageName : mLastPackagesResourceGranted) { - for (String newPackageName : packageNames) { - if (TextUtils.equals(newPackageName, packageName)) { - requestedFromLastPackages = true; - break; - } - } - } - } - mLastPackagesResourceGranted = packageNames; - if (!requestedFromLastPackages) { - closePip(); - } - } - } - - @Override - public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { - } - - PipMediaController getPipMediaController() { - return mPipMediaController; - } - - @Override - public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { - } - - @Override - public void onPipTransitionFinished(ComponentName activity, int direction) { - onPipTransitionFinishedOrCanceled(); - } - - @Override - public void onPipTransitionCanceled(ComponentName activity, int direction) { - onPipTransitionFinishedOrCanceled(); - } - - private void onPipTransitionFinishedOrCanceled() { - if (DEBUG) Log.d(TAG, "onPipTransitionFinishedOrCanceled()"); - - if (getState() == STATE_PIP_MENU) { - showPipMenu(); - } - } - - private String getStateDescription() { - return stateToName(mState); - } - - private static String stateToName(int state) { - switch (state) { - case STATE_NO_PIP: - return "NO_PIP"; - - case STATE_PIP: - return "PIP"; - - case STATE_PIP_MENU: - return "PIP_MENU"; - - default: - return "UNKNOWN(" + state + ")"; - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java new file mode 100644 index 000000000000..8bc60f9dbcd9 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.pip.tv; + +import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + +import android.annotation.IntDef; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.app.RemoteAction; +import android.app.TaskInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.ParceledListSlice; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; +import android.os.RemoteException; +import android.util.Log; +import android.view.DisplayInfo; + +import com.android.wm.shell.R; +import com.android.wm.shell.WindowManagerShellWrapper; +import com.android.wm.shell.common.TaskStackListenerCallback; +import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.pip.PinnedStackListenerForwarder; +import com.android.wm.shell.pip.Pip; +import com.android.wm.shell.pip.PipBoundsAlgorithm; +import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; +import com.android.wm.shell.pip.PipTaskOrganizer; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Manages the picture-in-picture (PIP) UI and states. + */ +public class TvPipController implements Pip, PipTaskOrganizer.PipTransitionCallback, + TvPipMenuController.Delegate, TvPipNotificationController.Delegate { + private static final String TAG = "TvPipController"; + static final boolean DEBUG = true; + + private static final int NONEXISTENT_TASK_ID = -1; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATE_" }, value = { + STATE_NO_PIP, + STATE_PIP, + STATE_PIP_MENU + }) + public @interface State {} + + /** + * State when there is no applications in Pip. + */ + private static final int STATE_NO_PIP = 0; + /** + * State when there is an applications in Pip and the Pip window located at its "normal" place + * (usually the bottom right corner). + */ + private static final int STATE_PIP = 1; + /** + * State when there is an applications in Pip and the Pip menu is open. In this state Pip window + * is usually moved from its "normal" position on the screen to the "menu" position - which is + * often at the middle of the screen, and gets slightly scaled up. + */ + private static final int STATE_PIP_MENU = 2; + + private final Context mContext; + + private final PipBoundsState mPipBoundsState; + private final PipBoundsAlgorithm mPipBoundsAlgorithm; + private final PipTaskOrganizer mPipTaskOrganizer; + private final PipMediaController mPipMediaController; + private final TvPipNotificationController mPipNotificationController; + private final TvPipMenuController mTvPipMenuController; + + private @State int mState = STATE_NO_PIP; + private int mPinnedTaskId = NONEXISTENT_TASK_ID; + + private int mResizeAnimationDuration; + + public TvPipController( + Context context, + PipBoundsState pipBoundsState, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipTaskOrganizer pipTaskOrganizer, + TvPipMenuController tvPipMenuController, + PipMediaController pipMediaController, + TvPipNotificationController pipNotificationController, + TaskStackListenerImpl taskStackListener, + WindowManagerShellWrapper wmShell) { + mContext = context; + + mPipBoundsState = pipBoundsState; + mPipBoundsState.setDisplayInfo(getDisplayInfo()); + mPipBoundsAlgorithm = pipBoundsAlgorithm; + + mPipMediaController = pipMediaController; + + mPipNotificationController = pipNotificationController; + mPipNotificationController.setDelegate(this); + + mTvPipMenuController = tvPipMenuController; + mTvPipMenuController.setDelegate(this); + + mPipTaskOrganizer = pipTaskOrganizer; + mPipTaskOrganizer.registerPipTransitionCallback(this); + + loadConfigurations(); + + registerTaskStackListenerCallback(taskStackListener); + registerWmShellPinnedStackListener(wmShell); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (DEBUG) Log.d(TAG, "onConfigurationChanged(), state=" + stateToName(mState)); + + if (isPipShown()) { + if (DEBUG) Log.d(TAG, " > closing Pip."); + closePip(); + } + + loadConfigurations(); + mPipNotificationController.onConfigurationChanged(mContext); + } + + /** + * Returns {@code true} if Pip is shown. + */ + @Override + public boolean isPipShown() { + return mState != STATE_NO_PIP; + } + + /** + * Starts the process if bringing up the Pip menu if by issuing a command to move Pip + * task/window to the "Menu" position. We'll show the actual Menu UI (eg. actions) once the Pip + * task/window is properly positioned in {@link #onPipTransitionFinished(ComponentName, int)}. + */ + @Override + public void showPictureInPictureMenu() { + if (DEBUG) Log.d(TAG, "showPictureInPictureMenu(), state=" + stateToName(mState)); + + if (mState != STATE_PIP) { + if (DEBUG) Log.d(TAG, " > cannot open Menu from the current state."); + return; + } + + setState(STATE_PIP_MENU); + resizePinnedStack(STATE_PIP_MENU); + } + + /** + * Moves Pip window to its "normal" position. + */ + @Override + public void movePipToNormalPosition() { + if (DEBUG) Log.d(TAG, "movePipToNormalPosition(), state=" + stateToName(mState)); + + setState(STATE_PIP); + resizePinnedStack(STATE_PIP); + } + + /** + * Opens the "Pip-ed" Activity fullscreen. + */ + @Override + public void movePipToFullscreen() { + if (DEBUG) Log.d(TAG, "movePipToFullscreen(), state=" + stateToName(mState)); + + mPipTaskOrganizer.exitPip(mResizeAnimationDuration); + onPipDisappeared(); + } + + /** + * Closes Pip window. + */ + @Override + public void closePip() { + if (DEBUG) Log.d(TAG, "closePip(), state=" + stateToName(mState)); + + removeTask(mPinnedTaskId); + onPipDisappeared(); + } + + /** + * Resizes the Pip task/window to the appropriate size for the given state. + * This is a legacy API. Now we expect that the state argument passed to it should always match + * the current state of the Controller. If it does not match an {@link IllegalArgumentException} + * will be thrown. However, if the passed state does match - we'll determine the right bounds + * to the state and will move Pip task/window there. + * + * @param state the to determine the Pip bounds. IMPORTANT: should always match the current + * state of the Controller. + */ + @Override + public void resizePinnedStack(@State int state) { + if (state != mState) { + throw new IllegalArgumentException("The passed state should match the current state!"); + } + if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + stateToName(mState)); + + final Rect newBounds; + switch (mState) { + case STATE_PIP_MENU: + newBounds = mPipBoundsState.getExpandedBounds(); + break; + + case STATE_PIP: + // Let PipBoundsAlgorithm figure out what the correct bounds are at the moment. + // Internally, it will get the "default" bounds from PipBoundsState and adjust them + // as needed to account for things like IME state (will query PipBoundsState for + // this information as well, so it's important to keep PipBoundsState up to date). + newBounds = mPipBoundsAlgorithm.getNormalBounds(); + break; + + case STATE_NO_PIP: + default: + return; + } + + mPipTaskOrganizer.scheduleAnimateResizePip(newBounds, mResizeAnimationDuration, null); + } + + @Override + public void registerSessionListenerForCurrentUser() { + mPipMediaController.registerSessionListenerForCurrentUser(); + } + + private void checkIfPinnedTaskAppeared() { + final TaskInfo pinnedTask = getPinnedTaskInfo(); + if (DEBUG) Log.d(TAG, "checkIfPinnedTaskAppeared(), task=" + pinnedTask); + if (pinnedTask == null) return; + mPinnedTaskId = pinnedTask.taskId; + setState(STATE_PIP); + + mPipMediaController.onActivityPinned(); + mPipNotificationController.show(pinnedTask.topActivity.getPackageName()); + } + + private void checkIfPinnedTaskIsGone() { + if (DEBUG) Log.d(TAG, "onTaskStackChanged()"); + + if (isPipShown() && getPinnedTaskInfo() == null) { + Log.w(TAG, "Pinned task is gone."); + onPipDisappeared(); + } + } + + private void onPipDisappeared() { + if (DEBUG) Log.d(TAG, "onPipDisappeared() state=" + stateToName(mState)); + + mPipNotificationController.dismiss(); + mTvPipMenuController.hideMenu(); + setState(STATE_NO_PIP); + mPinnedTaskId = NONEXISTENT_TASK_ID; + } + + @Override + public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { + if (DEBUG) Log.d(TAG, "onPipTransition_Started(), state=" + stateToName(mState)); + } + + @Override + public void onPipTransitionCanceled(ComponentName activity, int direction) { + if (DEBUG) Log.d(TAG, "onPipTransition_Canceled(), state=" + stateToName(mState)); + } + + @Override + public void onPipTransitionFinished(ComponentName activity, int direction) { + if (DEBUG) Log.d(TAG, "onPipTransition_Finished(), state=" + stateToName(mState)); + + if (mState == STATE_PIP_MENU) { + if (DEBUG) Log.d(TAG, " > show menu"); + mTvPipMenuController.showMenu(); + } + } + + private void setState(@State int state) { + if (DEBUG) { + Log.d(TAG, "setState(), state=" + stateToName(state) + ", prev=" + + stateToName(mState)); + } + mState = state; + } + + private void loadConfigurations() { + final Resources res = mContext.getResources(); + mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration); + // "Cache" bounds for the Pip menu as "expanded" bounds in PipBoundsState. We'll refer back + // to this value in resizePinnedStack(), when we are adjusting Pip task/window position for + // the menu. + mPipBoundsState.setExpandedBounds( + Rect.unflattenFromString(res.getString(R.string.pip_menu_bounds))); + } + + private DisplayInfo getDisplayInfo() { + final DisplayInfo displayInfo = new DisplayInfo(); + mContext.getDisplay().getDisplayInfo(displayInfo); + return displayInfo; + } + + private void registerTaskStackListenerCallback(TaskStackListenerImpl taskStackListener) { + taskStackListener.addListener(new TaskStackListenerCallback() { + @Override + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { + checkIfPinnedTaskAppeared(); + } + + @Override + public void onTaskStackChanged() { + checkIfPinnedTaskIsGone(); + } + + @Override + public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, + boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { + if (task.getWindowingMode() == WINDOWING_MODE_PINNED) { + if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()"); + + // If the "Pip-ed" Activity is launched again by Launcher or intent, make it + // fullscreen. + movePipToFullscreen(); + } + } + }); + } + + private void registerWmShellPinnedStackListener(WindowManagerShellWrapper wmShell) { + try { + wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedStackListener() { + @Override + public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { + if (DEBUG) { + Log.d(TAG, "onImeVisibilityChanged(), visible=" + imeVisible + + ", height=" + imeHeight); + } + + if (imeVisible == mPipBoundsState.isImeShowing() + && (!imeVisible || imeHeight == mPipBoundsState.getImeHeight())) { + // Nothing changed: either IME has been and remains invisible, or remains + // visible with the same height. + return; + } + mPipBoundsState.setImeVisibility(imeVisible, imeHeight); + // "Normal" Pip bounds may have changed, so if we are in the "normal" state, + // let's update the bounds. + if (mState == STATE_PIP) { + resizePinnedStack(STATE_PIP); + } + } + + @Override + public void onMovementBoundsChanged(boolean fromImeAdjustment) {} + + @Override + public void onActionsChanged(ParceledListSlice<RemoteAction> actions) { + if (DEBUG) Log.d(TAG, "onActionsChanged()"); + + mTvPipMenuController.setAppActions(actions); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Failed to register pinned stack listener", e); + } + } + + private static TaskInfo getPinnedTaskInfo() { + if (DEBUG) Log.d(TAG, "getPinnedTaskInfo()"); + try { + final TaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo( + WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); + if (DEBUG) Log.d(TAG, " > taskInfo=" + taskInfo); + return taskInfo; + } catch (RemoteException e) { + Log.e(TAG, "getRootTaskInfo() failed", e); + return null; + } + } + + private static void removeTask(int taskId) { + if (DEBUG) Log.d(TAG, "removeTask(), taskId=" + taskId); + try { + ActivityTaskManager.getService().removeTask(taskId); + } catch (Exception e) { + Log.e(TAG, "Atm.removeTask() failed", e); + } + } + + private static String stateToName(@State int state) { + switch (state) { + case STATE_NO_PIP: + return "NO_PIP"; + case STATE_PIP: + return "PIP"; + case STATE_PIP_MENU: + return "PIP_MENU"; + default: + // This can't happen. + throw new IllegalArgumentException("Unknown state " + state); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java index 9192cf14cd9b..470ab0c9c0e3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java @@ -42,7 +42,7 @@ import java.util.List; */ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener { private static final String TAG = "TvPipMenuController"; - private static final boolean DEBUG = PipController.DEBUG; + private static final boolean DEBUG = TvPipController.DEBUG; private final Context mContext; private final SystemWindows mSystemWindows; @@ -134,10 +134,18 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis } void hideMenu() { - if (DEBUG) Log.d(TAG, "hideMenu()"); + hideMenu(true); + } + + void hideMenu(boolean movePipWindow) { + if (DEBUG) Log.d(TAG, "hideMenu(), movePipWindow=" + movePipWindow); + + if (!isMenuVisible()) { + return; + } - if (isMenuVisible()) { - mMenuView.hide(); + mMenuView.hide(); + if (movePipWindow) { mDelegate.movePipToNormalPosition(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index f7b76c1ec745..e08ca52fd2ca 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -53,7 +53,7 @@ import java.util.List; */ public class TvPipMenuView extends FrameLayout implements View.OnClickListener { private static final String TAG = "TvPipMenuView"; - private static final boolean DEBUG = PipController.DEBUG; + private static final boolean DEBUG = TvPipController.DEBUG; private static final float DISABLED_ACTION_ALPHA = 0.54f; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java index 5716c7fc7162..ce4b60893367 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java @@ -19,14 +19,17 @@ package com.android.wm.shell.pip.tv; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.graphics.Bitmap; import android.media.MediaMetadata; +import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.wm.shell.R; @@ -39,22 +42,27 @@ import java.util.Objects; * <p>Once it's created, it will manage the PIP notification UI by itself except for handling * configuration changes. */ -public class PipNotification { - private static final boolean DEBUG = PipController.DEBUG; - private static final String TAG = "PipNotification"; +public class TvPipNotificationController { + private static final String TAG = "TvPipNotification"; + private static final boolean DEBUG = TvPipController.DEBUG; - private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); - public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP"; + // Referenced in com.android.systemui.util.NotificationChannels. + public static final String NOTIFICATION_CHANNEL = "TVPIP"; + private static final String NOTIFICATION_TAG = "TvPip"; - static final String ACTION_MENU = "PipNotification.menu"; - static final String ACTION_CLOSE = "PipNotification.close"; + private static final String ACTION_SHOW_PIP_MENU = + "com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU"; + private static final String ACTION_CLOSE_PIP = + "com.android.wm.shell.pip.tv.notification.action.CLOSE_PIP"; + private final Context mContext; private final PackageManager mPackageManager; private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; + private final ActionBroadcastReceiver mActionBroadcastReceiver; + private Delegate mDelegate; private String mDefaultTitle; - private int mDefaultIconResId; /** Package name for the application that owns PiP window. */ private String mPackageName; @@ -62,32 +70,56 @@ public class PipNotification { private String mMediaTitle; private Bitmap mArt; - public PipNotification(Context context, PipMediaController pipMediaController) { + public TvPipNotificationController(Context context, PipMediaController pipMediaController) { + mContext = context; mPackageManager = context.getPackageManager(); mNotificationManager = context.getSystemService(NotificationManager.class); - mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP) + mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL) .setLocalOnly(true) .setOngoing(false) .setCategory(Notification.CATEGORY_SYSTEM) + .setShowWhen(true) + .setSmallIcon(R.drawable.pip_icon) .extend(new Notification.TvExtender() - .setContentIntent(createPendingIntent(context, ACTION_MENU)) - .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); + .setContentIntent(createPendingIntent(context, ACTION_SHOW_PIP_MENU)) + .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE_PIP))); + + mActionBroadcastReceiver = new ActionBroadcastReceiver(); pipMediaController.addMetadataListener(this::onMediaMetadataChanged); onConfigurationChanged(context); } + void setDelegate(Delegate delegate) { + if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate); + if (mDelegate != null) { + throw new IllegalStateException( + "The delegate has already been set and should not change."); + } + if (delegate == null) { + throw new IllegalArgumentException("The delegate must not be null."); + } + + mDelegate = delegate; + } + void show(String packageName) { + if (mDelegate == null) { + throw new IllegalStateException("Delegate is not set."); + } + mPackageName = packageName; update(); + mActionBroadcastReceiver.register(); } void dismiss() { mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP); mNotified = false; mPackageName = null; + mActionBroadcastReceiver.unregister(); } private void onMediaMetadataChanged(MediaMetadata metadata) { @@ -101,11 +133,9 @@ public class PipNotification { * Called by {@link PipController} when the configuration is changed. */ void onConfigurationChanged(Context context) { - Resources res = context.getResources(); - mDefaultTitle = res.getString(R.string.pip_notification_unknown_title); - mDefaultIconResId = R.drawable.pip_icon; + mDefaultTitle = context.getResources().getString(R.string.pip_notification_unknown_title); if (mNotified) { - // update notification + // Update the notification. update(); } } @@ -113,9 +143,7 @@ public class PipNotification { private void update() { mNotified = true; mNotificationBuilder - .setShowWhen(true) .setWhen(System.currentTimeMillis()) - .setSmallIcon(mDefaultIconResId) .setContentTitle(getNotificationTitle()); if (mArt != null) { mNotificationBuilder.setStyle(new Notification.BigPictureStyle() @@ -178,4 +206,45 @@ public class PipNotification { return PendingIntent.getBroadcast(context, 0, new Intent(action), PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); } + + private class ActionBroadcastReceiver extends BroadcastReceiver { + final IntentFilter mIntentFilter; + { + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(ACTION_CLOSE_PIP); + mIntentFilter.addAction(ACTION_SHOW_PIP_MENU); + } + boolean mRegistered = false; + + void register() { + if (mRegistered) return; + + mContext.registerReceiver(this, mIntentFilter, UserHandle.USER_ALL); + mRegistered = true; + } + + void unregister() { + if (!mRegistered) return; + + mContext.unregisterReceiver(this); + mRegistered = false; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (DEBUG) Log.d(TAG, "on(Broadcast)Receive(), action=" + action); + + if (ACTION_SHOW_PIP_MENU.equals(action)) { + mDelegate.showPictureInPictureMenu(); + } else if (ACTION_CLOSE_PIP.equals(action)) { + mDelegate.closePip(); + } + } + } + + interface Delegate { + void showPictureInPictureMenu(); + void closePip(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 5213f6c80989..7ce71b0a1158 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2021 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.wm.shell; +package com.android.wm.shell.transition; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; @@ -42,6 +42,7 @@ import android.window.WindowOrganizer; import androidx.annotation.BinderThread; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.protolog.ShellProtoLogGroup; @@ -82,6 +83,7 @@ public class Transitions { mPlayerImpl = new TransitionPlayerImpl(); } + /** Register this transition handler with Core */ public void register(ShellTaskOrganizer taskOrganizer) { taskOrganizer.registerTransitionPlayer(mPlayerImpl); } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt index 75388bf2a189..5258e9030075 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt @@ -171,4 +171,4 @@ private val StatusBarNotification.deleteIntent: PendingIntent? get() = tvExtensions?.getParcelable("delete_intent") private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean = - tag == "PipNotification" && title == expectedTitle
\ No newline at end of file + tag == "TvPip" && title == expectedTitle
\ No newline at end of file diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml index 7000b95b35d6..15cecd6f46cc 100644 --- a/packages/PrintSpooler/res/values-or/strings.xml +++ b/packages/PrintSpooler/res/values-or/strings.xml @@ -80,10 +80,10 @@ <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>ଟି ପ୍ରିଣ୍ଟର୍ ଖୋଜିବା ପାଇଁ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ</item> </plurals> <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ପ୍ରିଣ୍ଟ କରାଯାଉଛି"</string> - <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> କ୍ୟାନ୍ସଲ୍ କରାଯାଉଛି"</string> + <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ବାତିଲ୍ କରାଯାଉଛି"</string> <string name="failed_notification_title_template" msgid="2256217208186530973">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> ପ୍ରିଣ୍ଟର୍ ତ୍ରୁଟି"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"ପ୍ରିଣ୍ଟର୍ ଦ୍ୱାରା ରୋକାଯାଇଥିବା <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> - <string name="cancel" msgid="4373674107267141885">"କ୍ୟାନ୍ସଲ୍"</string> + <string name="cancel" msgid="4373674107267141885">"ବାତିଲ୍"</string> <string name="restart" msgid="2472034227037808749">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ପ୍ରିଣ୍ଟର୍କୁ କୌଣସି ସଂଯୋଗ ନାହିଁ"</string> <string name="reason_unknown" msgid="5507940196503246139">"ଅଜଣା"</string> diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index 66d0ac756bf5..80761591e0bf 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -38,7 +38,7 @@ <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജ് ചെയ്യുന്നു"</string> <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു"</string> <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു"</string> - <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററി നില ഒപ്റ്റിമൈസ് ചെയ്യുന്നു"</string> + <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററിയുടെ ആയുസിനായി ഒപ്റ്റിമൈസ് ചെയ്യുന്നു"</string> <string name="keyguard_low_battery" msgid="1868012396800230904">"നിങ്ങളുടെ ചാർജർ കണക്റ്റുചെയ്യുക."</string> <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string> <string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്വർക്ക് ലോക്കുചെയ്തു"</string> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index fe4ba63fe6c3..0beb286b6f63 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuwe gebruiker"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nie gekoppel nie"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk nie"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi af"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Wys profiel"</string> <string name="user_add_user" msgid="4336657383006913022">"Voeg gebruiker by"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nuwe gebruiker"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Beëindig gastesessie?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Beëindig sessie"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 9149aa636180..f56e84ae1606 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ተጠቃሚ"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"አዲስ ተጠቃሚ"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"በይነመረብ"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"አልተገናኘም"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ምንም አውታረ መረብ የለም"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ጠፍቷል"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"መገለጫ አሳይ"</string> <string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string> <string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"የእንግዳ ክፍለ-ጊዜ ይብቃ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ክፍለ-ጊዜን አብቃ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 0146fcddf4fd..aaaf7788c5c3 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -357,8 +357,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"المستخدم"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"مستخدم جديد"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"الإنترنت"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ليست متصلة"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"لا تتوفر شبكة"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"إيقاف Wi-Fi"</string> @@ -464,11 +463,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"عرض الملف الشخصي"</string> <string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string> <string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"هل تريد إنهاء جلسة الضيف؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"إنهاء الجلسة"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 3c206f2949a3..7e3e3cb04280 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -456,11 +456,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"প্ৰ\'ফাইল দেখুৱাওক"</string> <string name="user_add_user" msgid="4336657383006913022">"ব্যৱহাৰকাৰী যোগ কৰক"</string> <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যৱহাৰকাৰী"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"অতিথিৰ ছেশ্বন সমাপ্ত কৰিবনে?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ছেশ্বন সমাপ্ত কৰক"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"আপোনাক পুনৰাই স্বাগতম জনাইছোঁ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 67e1718a03fb..6c22cc34b83e 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"İstifadəçi"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni istifadəçi"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlantı yoxdur"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Şəbəkə yoxdur"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi sönülüdür"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string> <string name="user_add_user" msgid="4336657383006913022">"İstifadəçi əlavə edin"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Yeni istifadəçi"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Qonaq sessiyası bitirilsin?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sessiyanı bitirin"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayın"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index ae8ffbfbe304..2f3d6d28526e 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Veza nije uspostavljena"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaži profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Želite da završite sesiju gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index b90d57e7ff5d..925e86a8916b 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Карыстальнік"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новы карыстальнік"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтэрнэт"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма падключэння"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма сеткi"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi адключаны"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Паказаць профіль"</string> <string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завяршыць гасцявы сеанс?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завяршыць сеанс"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index bfc8ef1d1151..6a683c742931 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Потребител"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов потребител"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма връзка"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма мрежа"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е изключен"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показване на потребителския профил"</string> <string name="user_add_user" msgid="4336657383006913022">"Добавяне на потребител"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Нов потребител"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Да се прекрати ли сесията като гост?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Прекратяване на сесията"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index c41a43404628..953ec006016b 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ব্যবহারকারী"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যবহারকারী"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ওয়াই-ফাই"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ইন্টারনেট"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"সংযুক্ত নয়"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"কোনো নেটওয়ার্ক নেই"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ওয়াই-ফাই বন্ধ"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"প্রোফাইল দেখান"</string> <string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string> <string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"গেস্ট সেশন শেষ করতে চান?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"সেশন শেষ করুন"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি অবিরত রাখতে চান?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 9a2877351c51..6bf185230602 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaži profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Završiti sesiju gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i svi podaci iz ove sesije bit će izbrisani."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 426005af098a..71105cc55b50 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuari"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuari nou"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Desconnectat"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hi ha cap xarxa"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desconnectada"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra el perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vols finalitzar la sessió de convidat?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalitza la sessió"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 3e015ec7c720..65e676737ca2 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Uživatel"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový uživatel"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepřipojeno"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žádná síť"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi vypnuta"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobrazit profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ukončit relaci hosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ukončit relaci"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 8fd48b1bdd02..e50aa57e70cb 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Bruger"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruger"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke forbundet"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Intet netværk"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi slået fra"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vil du afslutte gæstesessionen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Afslut sessionen"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 84b63ba2db37..3cdebf9c80d9 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Nutzer"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Neuer Nutzer"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nicht verbunden"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Kein Netz"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN aus"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil öffnen"</string> <string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Gastsitzung beenden?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sitzung beenden"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index bec78c0e57d6..c6ae7f4b0c51 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Χρήστης"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Νέος χρήστης"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Διαδίκτυο"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Μη συνδεδεμένο"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Κανένα δίκτυο"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ανενεργό"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Εμφάνιση προφίλ"</string> <string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Λήξη περιόδου σύνδεσης επισκέπτη;"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Λήξη περιόδου σύνδεσης"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Επισκέπτη , καλώς όρισες ξανά!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 21cac18abeb5..ea25ec6e771c 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 7ac4c0df0ca1..a373a5c0061d 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 21cac18abeb5..ea25ec6e771c 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 21cac18abeb5..ea25ec6e771c 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 2f30c412a159..101d11245ffc 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 7ef9cdb96df7..1fc1609c7dcc 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuario nuevo"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Sin conexión"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sin red"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivada"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 6c6b511e2fe4..dd36a64812ab 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuevo usuario"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"No conectado"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hay red."</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivado"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index c64a07e3b61b..fb27be994265 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Kasutaja"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uus kasutaja"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ühendus puudub"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Võrku pole"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi-ühendus on väljas"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Kuva profiil"</string> <string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Kas lõpetada külastajaseanss?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Lõpeta seanss"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5047cf17fefd..d8b21c633dfa 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Erabiltzailea"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Erabiltzaile berria"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifia"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Konektatu gabe"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ez dago sarerik"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi konexioa desaktibatuta"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 34c6bf66f64c..df306f83e16e 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"کاربر"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"کاربر جدید"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"اینترنت"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"متصل نیست"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"شبکهای موجود نیست"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi خاموش است"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"نمایش نمایه"</string> <string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string> <string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"جلسه مهمان تمام شود؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"پایان جلسه"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد میگوییم!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا میخواهید جلسهتان را ادامه دهید؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 5486e39133d8..4e0af373f572 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Käyttäjä"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uusi käyttäjä"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ei yhteyttä"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ei verkkoa"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-yhteys pois käytöstä"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Näytä profiili"</string> <string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Lopetetaanko Vierailija-käyttökerta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Lopeta käyttökerta"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 63f65e08e189..8c944a4a0e0f 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Mettre fin à la session d\'invité?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Fermer la session"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index ebf199bfae90..7ad239dc4ee2 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Fermer la session Invité ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Fermer la session"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 36f7f4cd9fb7..145b3c06b387 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuario"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non conectada"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Non hai rede"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi desactivada"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Queres finalizar a sesión de invitado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalizar sesión"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 66423e46c4e5..ea7af17dcb6a 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"વપરાશકર્તા"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"નવો વપરાશકર્તા"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"વાઇ-ફાઇ"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ઇન્ટરનેટ"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"કનેક્ટ થયેલ નથી"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"કોઈ નેટવર્ક નથી"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"વાઇ-ફાઇ બંધ"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"પ્રોફાઇલ બતાવો"</string> <string name="user_add_user" msgid="4336657383006913022">"વપરાશકર્તા ઉમેરો"</string> <string name="user_new_user_name" msgid="2019166282704195789">"નવો વપરાશકર્તા"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"શું અતિથિ સત્ર સમાપ્ત કરીએ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"સત્ર સમાપ્ત કરો"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ કરવા માંગો છો?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 65cba2f9dc09..a8bed5b26401 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"उपयोगकर्ता"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"नया उपयोगकर्ता"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाई-फ़ाई"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"इंटरनेट"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट नहीं है"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"कोई नेटवर्क नहीं"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाई-फ़ाई बंद"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"प्रोफ़ाइल दिखाएं"</string> <string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string> <string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"मेहमान के तौर पर ब्राउज़ करने का सेशन खत्म करना चाहते हैं?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"सेशन खत्म करें"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथि, आपका फिर से स्वागत है!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"क्या आप अपना सत्र जारी रखना चाहते हैं?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 7d60619e2f02..4ffa5b2e04ff 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi isključen"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string> <string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Završiti gostujuću sesiju?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Završi sesiju"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 2ee8913f00d1..cff5b0dc65b3 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Felhasználó"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Új felhasználó"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nincs kapcsolat"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nincs hálózat"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi kikapcsolva"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil megjelenítése"</string> <string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Befejezi a vendég munkamenetet?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Munkamenet befejezése"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 18af1eaf17e3..91ffe7308a91 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Օգտատեր"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Նոր օգտատեր"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Ինտերնետ"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Միացված չէ"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ցանց չկա"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-ը անջատված է"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 4a048bb638ef..f9e7397993dc 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baru"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Terhubung"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tidak Ada Jaringan"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Mati"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tampilkan profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Akhiri sesi tamu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Akhiri sesi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 10e11fc64d7b..db5dac43a42a 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Notandi"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nýr notandi"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Engin tenging"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ekkert net"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Slökkt á Wi-Fi"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Sýna snið"</string> <string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ljúka gestalotu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ljúka lotu"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 24e3f474f1fe..86e65bbc3629 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -63,7 +63,7 @@ <string name="usb_debugging_allow" msgid="1722643858015321328">"Consenti"</string> <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Debug USB non consentito"</string> <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"L\'utente che ha eseguito l\'accesso a questo dispositivo non può attivare il debug USB. Per utilizzare questa funzione, passa all\'utente principale."</string> - <string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire debug wireless su questa rete?"</string> + <string name="wifi_debugging_title" msgid="7300007687492186076">"Consentire il debug wireless su questa rete?"</string> <string name="wifi_debugging_message" msgid="5461204211731802995">"Nome della rete (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nIndirizzo Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string> <string name="wifi_debugging_always" msgid="2968383799517975155">"Consenti sempre su questa rete"</string> <string name="wifi_debugging_allow" msgid="4573224609684957886">"Consenti"</string> @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Utente"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuovo utente"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connessa"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nessuna rete"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi disattivato"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra profilo"</string> <string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vuoi terminare la sessione Ospite?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Termina sessione"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bentornato, ospite."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 76dbdf99ca50..8548dae09ee2 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"משתמש"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"משתמש חדש"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"אינטרנט"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"אין חיבור"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"אין רשת"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi כבוי"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"הצג פרופיל"</string> <string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string> <string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"להפסיק את הגלישה כאורח?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בפעילות זו באתר יימחקו."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"הפסקת הגלישה"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ברצוני להתחיל מחדש"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index b4edfe5c38dc..6cd560854960 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ユーザー"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新しいユーザー"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"インターネット"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"接続されていません"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ネットワークなし"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi OFF"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"プロファイルを表示"</string> <string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ゲスト セッションを終了しますか?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"セッションを終了"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 26bde65e0ba3..52d9f0e77451 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"მომხმარებელი"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ახალი მომხმარებელი"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ინტერნეტი"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"არ არის დაკავშირებული."</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ქსელი არ არის"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi გამორთულია"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"პროფილის ჩვენება"</string> <string name="user_add_user" msgid="4336657383006913022">"მომხმარებლის დამატება"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ახალი მომხმარებელი"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"დასრულდეს სტუმრის სესია?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"სესიის დასრულება"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 9ce0a29649dc..fcf87434ad3b 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Пайдаланушы"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңа пайдаланушы"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Жалғанбаған"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желі жоқ"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өшірулі"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профильді көрсету"</string> <string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Қонақ сеансы аяқталсын ба?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сеансты аяқтау"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 1e6c7fa6ebea..e92bf9bda905 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"អ្នកប្រើ"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"អ្នកប្រើថ្មី"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"អ៊ីនធឺណិត"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"មិនបានតភ្ជាប់"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"គ្មានបណ្ដាញ"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"វ៉ាយហ្វាយបានបិទ"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"បង្ហាញប្រវត្តិរូប"</string> <string name="user_add_user" msgid="4336657383006913022">"បន្ថែមអ្នកប្រើ"</string> <string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើថ្មី"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"បញ្ចប់វគ្គភ្ញៀវឬ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ទិន្នន័យ និងកម្មវិធីទាំងអស់ក្នុងសម័យនេះនឹងត្រូវបានលុប។"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"បញ្ចប់វគ្គ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"សូមស្វាគមន៍ការត្រឡប់មកវិញ, ភ្ញៀវ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"តើអ្នកចង់បន្តសម័យរបស់អ្នក?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើម"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 2958b2947de0..d7a0adc85935 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ಬಳಕೆದಾರ"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ಹೊಸ ಬಳಕೆದಾರರು"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"ವೈ-ಫೈ"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ಇಂಟರ್ನೆಟ್"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ನೆಟ್ವರ್ಕ್ ಇಲ್ಲ"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ವೈ-ಫೈ ಆಫ್"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ಪ್ರೊಫೈಲ್ ತೋರಿಸು"</string> <string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ಅತಿಥಿ ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸುವುದೇ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ಸೆಷನ್ ಅಂತ್ಯಗೊಳಿಸಿ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index cd613b647e38..54bcfb978ac9 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"사용자"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"인터넷"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"연결되어 있지 않음"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"네트워크가 연결되지 않음"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 꺼짐"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"프로필 표시"</string> <string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string> <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"게스트 세션을 종료하시겠습니까?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"세션 종료"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 다시 시작"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index e6053411b74a..d513380f9355 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Колдонуучу"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңы колдонуучу"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Байланышкан жок"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желе жок"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өчүк"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профилди көрсөтүү"</string> <string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Конок сеансы бүтүрүлсүнбү?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана дайындар өчүрүлөт."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сеансты бүтүрүү"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен, конок!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index b8cc3ded31e8..7e595cd83176 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ຜູ້ໃຊ້"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ຜູ່ໃຊ້ໃໝ່"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ອິນເຕີເນັດ"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ບໍ່ມີເຄືອຂ່າຍ"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ປິດ"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ສະແດງໂປຣໄຟລ໌"</string> <string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ສິ້ນສຸດເຊດຊັນແຂກບໍ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ສິ້ນສຸດເຊດຊັນ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນດີຕ້ອນຮັບກັບມາ, ຜູ່ຢ້ຽມຢາມ!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານຕ້ອງການສືບຕໍ່ເຊດຊັນຂອງທ່ານບໍ່?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 8a32436f2c0c..e0c27a96de44 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Naudotojas"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Naujas naudotojas"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internetas"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neprisijungta"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tinklo nėra"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"„Wi-Fi“ išjungta"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Rodyti profilį"</string> <string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Baigti svečio sesiją?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Baigti sesiją"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 56ce376dd147..ff36f51b5603 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Lietotājs"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Jauns lietotājs"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internets"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nav izveidots savienojums"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nav tīkla"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ir izslēgts"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Parādīt profilu"</string> <string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vai beigt viesa sesiju?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Beigt sesiju"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index fc83bb7ee46d..203d8b90ae52 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов корисник"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не е поврзано"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мрежа"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е исклучено"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Прикажи го профилот"</string> <string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Да се заврши гостинската сесија?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Заврши ја сесијата"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 9cd041236c36..77925ae0c268 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ഉപയോക്താവ്"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"പുതിയ ഉപയോക്താവ്"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"വൈഫൈ"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ഇന്റർനെറ്റ്"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"കണക്റ്റ് ചെയ്തിട്ടില്ല"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"നെറ്റ്വർക്ക് ഒന്നുമില്ല"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"വൈഫൈ ഓഫുചെയ്യുക"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"പ്രൊഫൈൽ കാണിക്കുക"</string> <string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്ക്കുക"</string> <string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"അതിഥി സെഷൻ അവസാനിപ്പിക്കണോ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ അപ്ലിക്കേഷനുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"സെഷൻ അവസാനിപ്പിക്കുക"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥിയ്ക്ക് വീണ്ടും സ്വാഗതം!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index b0159b027611..c772294a6bdf 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Хэрэглэгч"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Шинэ хэрэглэгч"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернэт"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Холбогдоогүй"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Сүлжээгүй"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi унтарсан"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Профайлыг харуулах"</string> <string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Зочны сургалтыг дуусгах уу?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ сешний бүх апп болон дата устах болно."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Сургалтыг дуусгах"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Тавтай морилно уу!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index b9b525ead63c..d3e360147d0f 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baharu"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Disambungkan"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tiada Rangkaian"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Dimatikan"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tunjuk profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Tamatkan sesi tetamu?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Tamatkan sesi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 9801ec60c89e..0c1f9cbbc060 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"အသုံးပြုသူ"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"အသုံးပြုသူ အသစ်"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"အင်တာနက်"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ချိတ်ဆက်မထားပါ"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ကွန်ရက်မရှိပါ"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ဝိုင်ဖိုင်ပိတ်ရန်"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ပရိုဖိုင်ကို ပြရန်"</string> <string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string> <string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ဧည့်သည်စက်ရှင်ကို အဆုံးသတ်မလား။"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"သတ်မှတ်ပေးထားသည့်အချိန် ပြီးဆုံးပြီ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ပြန်လာတာ ကြိုဆိုပါသည်၊ ဧည့်သည်!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်သည် သင်၏ ချိတ်ဆက်မှုကို ဆက်ပြုလုပ် လိုပါသလား?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"အစမှ ပြန်စပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 67242865b649..565e7fea215d 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Bruker"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruker"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internett"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke tilkoblet"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ingen nettverk"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi er av"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vil du avslutte gjesteøkten?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Avslutt økten"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index c104ffdf0dcd..9d95cf042dad 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"प्रयोगकर्ता"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"नयाँ प्रयोगकर्ता"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"इन्टरनेट"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"जोडिएको छैन"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क छैन"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi बन्द"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"प्रोफाइल देखाउनुहोस्"</string> <string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string> <string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"अतिथिको सत्र अन्त्य गर्ने हो?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यस सत्रमा सबै एपहरू र डेटा मेटाइनेछ।"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"सत्र अन्त्य गर्नुहोस्"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"पुनः स्वागत, अतिथि!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 7d878170283f..f598fa3fae09 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nieuwe gebruiker"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Niet verbonden"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi uit"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profiel weergeven"</string> <string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Gastsessie beëindigen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Sessie beëindigen"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 7d7b84f785f1..1e07dd4b785e 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -456,11 +456,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ପ୍ରୋଫାଇଲ୍ ଦେଖାନ୍ତୁ"</string> <string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ଅତିଥି ସେସନ୍ ଶେଷ କରିବେ?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ଅବଧିର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"ସେସନ୍ ଶେଷ କରନ୍ତୁ"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ଅବଧି ଜାରି ରଖିବାକୁ ଚାହାନ୍ତି କି?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 8a19e285463e..561e70dd14cb 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Użytkownik"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nowy użytkownik"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Brak połączenia"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Brak sieci"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi wyłączone"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaż profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Zakończyć sesję gościa?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Zakończ sesję"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, gościu!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 57b924d4e6f8..7fe53d348e15 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Encerrar sessão de visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Encerrar sessão"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index e39f757ce416..dd154e8ad684 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizador"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo utilizador"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não Ligado"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem Rede"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Desligado"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Pretende terminar a sessão de convidado?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as aplicações e dados desta sessão serão eliminados."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Terminar sessão"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, caro(a) convidado(a)!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 57b924d4e6f8..7fe53d348e15 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string> <string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Encerrar sessão de visitante?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Encerrar sessão"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index acbe80140c2f..317fc098d522 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizator"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Utilizator nou"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neconectată"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nicio rețea"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi deconectat"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afișați profilul"</string> <string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Încheiați sesiunea pentru invitați?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Încheiați sesiunea"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index c59bd2ae727d..bbb014e82b07 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Пользователь"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новый пользователь"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Нет соединения"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нет сети"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi выкл."</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показать профиль."</string> <string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завершить гостевой сеанс?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завершить сеанс"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index a49ca863b3fa..a7a2bb7dbbff 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"පරිශීලක"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"නව පරිශීලකයා"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"අන්තර්ජාලය"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"සම්බන්ධ වී නොමැත"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ජාලයක් නැත"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi අක්රියයි"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"පැතිකඩ පෙන්වන්න"</string> <string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string> <string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"ආරාධිත සැසිය අවසන් කරන්නද?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"සැසිය අවසන් කරන්න"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්යද?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index fe63b70f1c46..7eb5297a43f1 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Používateľ"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový používateľ"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi‑Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepripojené"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žiadna sieť"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Sieť Wi‑Fi je vypnutá"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobraziť profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Chcete ukončiť reláciu hosťa?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ukončiť reláciu"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 85956d6d0c72..6d23f26a6c8d 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Uporabnik"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nov uporabnik"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Povezava ni vzpostavljena"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ni omrežja"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi izklopljen"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string> <string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Želite končati sejo gosta?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Končaj sejo"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 733db0e018a8..7e89b93cec82 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Përdoruesi"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Përdorues i ri"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nuk është i lidhur"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nuk ka rrjet"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi është i çaktivizuar"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index c5414a4e3f80..af5175c2bbf6 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -354,8 +354,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нови корисник"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Интернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Веза није успостављена"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мреже"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi је искључен"</string> @@ -458,11 +457,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Прикажи профил"</string> <string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Желите да завршите сесију госта?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Заврши сесију"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index d2c993a0985a..41bca7c90b32 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Användare"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny användare"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ej ansluten"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Inget nätverk"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi av"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Visa profil"</string> <string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Vill du avsluta gästsessionen?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Avsluta session"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka gäst!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 29045f3d69ae..f122013cc150 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Mtumiaji"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Mtumiaji mpya"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Intaneti"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Haijaunganishwa"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Hakuna Mtandao"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Imezimwa"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Onyesha wasifu"</string> <string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ungependa kumaliza kipindi cha mgeni?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Maliza kipindi"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena, mwalikwa!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza tena"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 2ca67201d387..c076a031b93f 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"பயனர்"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"புதியவர்"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"வைஃபை"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"இணையம்"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"இணைக்கப்படவில்லை"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"நெட்வொர்க் இல்லை"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"வைஃபையை முடக்கு"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"சுயவிவரத்தைக் காட்டு"</string> <string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string> <string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"விருந்தினர் அமர்வை நிறைவுசெய்யவா?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா பயன்பாடுகளும், தரவும் நீக்கப்படும்."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"அமர்வை நிறைவுசெய்"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 9ce5fc745580..fca51077d06f 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"వినియోగదారు"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"కొత్త వినియోగదారు"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"ఇంటర్నెట్"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"కనెక్ట్ చేయబడలేదు"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"నెట్వర్క్ లేదు"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ఆఫ్లో ఉంది"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"ప్రొఫైల్ని చూపు"</string> <string name="user_add_user" msgid="4336657383006913022">"వినియోగదారుని జోడించండి"</string> <string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"గెస్ట్ సెషన్ను ముగించాలా?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"సెషన్ను ముగించు"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"పునఃస్వాగతం, అతిథి!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్ని కొనసాగించాలనుకుంటున్నారా?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 900012eb267d..c909d379dedc 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"ผู้ใช้"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"ผู้ใช้ใหม่"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"อินเทอร์เน็ต"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ไม่ได้เชื่อมต่อ"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ไม่มีเครือข่าย"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ปิด WiFi"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"แสดงโปรไฟล์"</string> <string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string> <string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"จบเซสชันผู้เยี่ยมชมใช่ไหม"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"จบเซสชัน"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับท่านผู้เยี่ยมชมกลับมาอีกครั้ง!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index f531de5a89de..2e75fa3de905 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Bagong user"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Hindi Nakakonekta"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Walang Network"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Naka-off ang Wi-Fi"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Ipakita ang profile"</string> <string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Tapusin ang session ng bisita?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Tapusin ang session"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Maligayang pagbabalik, bisita!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index ba70531a89f3..98552b1b135d 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Kullanıcı"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni kullanıcı"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Kablosuz"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"İnternet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlı Değil"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ağ yok"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Kablosuz Kapalı"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profili göster"</string> <string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Misafir oturumu sonlandırılsın mı?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Oturumu sonlandır"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Tekrar hoş geldiniz sayın misafir!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index b2ae569cf26c..b70d36af64c2 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -355,8 +355,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Користувач"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новий користувач"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Інтернет"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не під’єднано."</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Немає мережі"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi вимкнено"</string> @@ -460,11 +459,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Показати профіль"</string> <string name="user_add_user" msgid="4336657383006913022">"Додати користувача"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Новий користувач"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Завершити сеанс у режимі \"Гість\"?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Завершити сеанс"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 06a448b25579..bbadf6a7d5f1 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"صارف"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"نیا صارف"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"انٹرنیٹ"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"مربوط نہیں ہے"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"کوئی نیٹ ورک نہیں ہے"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi آف ہے"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"پروفائل دکھائیں"</string> <string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string> <string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"مہمان سیشن ختم کریں؟"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"سیشن ختم کریں"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index e1add6503412..a20676dca577 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Foydalanuvchi"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yangi foydalanuvchi"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ulanmagan"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tarmoq mavjud emas"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi o‘chiq"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 021044d29b34..5de7df6a5d69 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Người dùng"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Người dùng mới"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internet"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Chưa được kết nối"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Không có mạng nào"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Tắt Wi-Fi"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Hiển thị hồ sơ"</string> <string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Kết thúc phiên khách?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Kết thúc phiên"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 60acb839b33a..7f3f3943e3c5 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"用户"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新用户"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"互联网"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未连接"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"无网络"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN:关闭"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"显示个人资料"</string> <string name="user_add_user" msgid="4336657383006913022">"添加用户"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要结束访客会话吗?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"结束会话"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index db55580872f4..485f1cf786be 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"互聯網"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網絡"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 關閉"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"顯示個人檔案"</string> <string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要結束訪客工作階段嗎?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"結束工作階段"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 1487ad33d12f..1edeacd1a843 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"網際網路"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網路"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 已關閉"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"顯示設定檔"</string> <string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string> <string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"要結束訪客工作階段嗎?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"結束工作階段"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index b0f084b7f83d..58baebc27cc6 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -353,8 +353,7 @@ <string name="quick_settings_user_title" msgid="8673045967216204537">"Umsebenzisi"</string> <string name="quick_settings_user_new_user" msgid="3347905871336069666">"Umsebenzisi omusha"</string> <string name="quick_settings_wifi_label" msgid="2879507532983487244">"I-Wi-Fi"</string> - <!-- no translation found for quick_settings_internet_label (6603068555872455463) --> - <skip /> + <string name="quick_settings_internet_label" msgid="6603068555872455463">"I-inthanethi"</string> <string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Akuxhunyiwe"</string> <string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ayikho inethiwekhi"</string> <string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"I-Wi-Fi icimile"</string> @@ -456,11 +455,9 @@ <string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Bonisa iphrofayela"</string> <string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string> <string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string> - <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) --> - <skip /> + <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Misa isikhathi sesihambeli?"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string> - <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) --> - <skip /> + <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Phothula iseshini"</string> <string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string> <string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string> <string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string> diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index c2ba3440f19f..aa8d710e7570 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -130,7 +130,7 @@ public class ScreenPinningRequest implements View.OnClickListener, } } - private WindowManager.LayoutParams getWindowLayoutParams() { + protected WindowManager.LayoutParams getWindowLayoutParams() { final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java index 3811ca929f6e..bbc4b780bc52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/FeatureFlags.java @@ -50,18 +50,26 @@ public class FeatureFlags { @Inject public FeatureFlags(@Background Executor executor) { DeviceConfig.addOnPropertiesChangedListener( - "systemui", + /* namespace= */ "systemui", executor, this::onPropertiesChanged); } public boolean isNewNotifPipelineEnabled() { - return getDeviceConfigFlag("notification.newpipeline.enabled", true); + return getDeviceConfigFlag("notification.newpipeline.enabled", /* defaultValue= */ true); } public boolean isNewNotifPipelineRenderingEnabled() { return isNewNotifPipelineEnabled() - && getDeviceConfigFlag("notification.newpipeline.rendering", false); + && getDeviceConfigFlag("notification.newpipeline.rendering", /* defaultValue= */ + false); + } + + /** + * Flag used for guarding development of b/171917882. + */ + public boolean isTwoColumnNotificationShadeEnabled() { + return getDeviceConfigFlag("notification.twocolumn", /* defaultValue= */ false); } private void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { @@ -76,7 +84,7 @@ public class FeatureFlags { synchronized (mCachedDeviceConfigFlags) { Boolean flag = mCachedDeviceConfigFlags.get(key); if (flag == null) { - flag = DeviceConfig.getBoolean("systemui", key, defaultValue); + flag = DeviceConfig.getBoolean(/* namespace= */ "systemui", key, defaultValue); mCachedDeviceConfigFlags.put(key, flag); } return flag; diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 0d63324966fd..0ba072e9e72f 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -25,7 +25,7 @@ import android.provider.Settings; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.SystemUI; -import com.android.wm.shell.pip.tv.PipNotification; +import com.android.wm.shell.pip.tv.TvPipNotificationController; import java.util.Arrays; @@ -36,7 +36,7 @@ public class NotificationChannels extends SystemUI { public static String GENERAL = "GEN"; public static String STORAGE = "DSK"; public static String BATTERY = "BAT"; - public static String TVPIP = PipNotification.NOTIFICATION_CHANNEL_TVPIP; + public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP" public static String HINTS = "HNT"; public NotificationChannels(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java index 4d3af9c01153..8a79acef756c 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java @@ -32,9 +32,9 @@ import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; -import com.android.wm.shell.pip.tv.PipController; -import com.android.wm.shell.pip.tv.PipNotification; +import com.android.wm.shell.pip.tv.TvPipController; import com.android.wm.shell.pip.tv.TvPipMenuController; +import com.android.wm.shell.pip.tv.TvPipNotificationController; import java.util.Optional; @@ -55,31 +55,24 @@ public abstract class TvPipModule { PipTaskOrganizer pipTaskOrganizer, TvPipMenuController tvPipMenuController, PipMediaController pipMediaController, - PipNotification pipNotification, + TvPipNotificationController tvPipNotificationController, TaskStackListenerImpl taskStackListener, WindowManagerShellWrapper windowManagerShellWrapper) { return Optional.of( - new PipController( + new TvPipController( context, pipBoundsState, pipBoundsAlgorithm, pipTaskOrganizer, tvPipMenuController, pipMediaController, - pipNotification, + tvPipNotificationController, taskStackListener, windowManagerShellWrapper)); } @WMSingleton @Provides - static PipNotification providePipNotification(Context context, - PipMediaController pipMediaController) { - return new PipNotification(context, pipMediaController); - } - - @WMSingleton - @Provides static PipBoundsAlgorithm providePipBoundsHandler(Context context, PipBoundsState pipBoundsState) { return new PipBoundsAlgorithm(context, pipBoundsState); @@ -93,7 +86,7 @@ public abstract class TvPipModule { @WMSingleton @Provides - static TvPipMenuController providesPipTvMenuController( + static TvPipMenuController providesTvPipMenuController( Context context, PipBoundsState pipBoundsState, SystemWindows systemWindows, @@ -103,15 +96,22 @@ public abstract class TvPipModule { @WMSingleton @Provides + static TvPipNotificationController provideTvPipNotificationController(Context context, + PipMediaController pipMediaController) { + return new TvPipNotificationController(context, pipMediaController); + } + + @WMSingleton + @Provides static PipTaskOrganizer providePipTaskOrganizer(Context context, - TvPipMenuController tvMenuController, + TvPipMenuController tvPipMenuController, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm, PipSurfaceTransactionHelper pipSurfaceTransactionHelper, Optional<LegacySplitScreen> splitScreenOptional, DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) { return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm, - tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional, + tvPipMenuController, pipSurfaceTransactionHelper, splitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer); } } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java index 1d3f26e73080..e20cd44974bb 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java @@ -21,7 +21,6 @@ import android.view.IWindowManager; import com.android.systemui.dagger.WMSingleton; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.Transitions; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.ShellExecutor; @@ -32,6 +31,7 @@ import com.android.wm.shell.common.TransactionPool; import com.android.wm.shell.common.annotations.ShellMainThread; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController; +import com.android.wm.shell.transition.Transitions; import dagger.Module; import dagger.Provides; diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index b0bb3fd88ae5..572b15d5215a 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -42,7 +42,6 @@ import com.android.wm.shell.ShellInitImpl; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.TaskViewFactory; import com.android.wm.shell.TaskViewFactoryController; -import com.android.wm.shell.Transitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.bubbles.BubbleController; @@ -71,6 +70,7 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.pip.phone.PipAppOpsListener; import com.android.wm.shell.pip.phone.PipTouchHandler; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -176,6 +176,7 @@ public abstract class WMShellBaseModule { Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<AppPairs> appPairsOptional, FullscreenTaskListener fullscreenTaskListener, + Transitions transitions, @ShellMainThread ShellExecutor shellMainExecutor) { return ShellInitImpl.create(displayImeController, dragAndDropController, @@ -183,6 +184,7 @@ public abstract class WMShellBaseModule { legacySplitScreenOptional, appPairsOptional, fullscreenTaskListener, + transitions, shellMainExecutor); } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java index 509419e5d11c..e635e1708841 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java @@ -17,13 +17,10 @@ package com.android.systemui.wmshell; import android.content.Context; -import android.os.Handler; import android.view.IWindowManager; import com.android.systemui.dagger.WMSingleton; -import com.android.systemui.dagger.qualifiers.Main; import com.android.wm.shell.ShellTaskOrganizer; -import com.android.wm.shell.Transitions; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.apppairs.AppPairs; import com.android.wm.shell.apppairs.AppPairsController; @@ -49,9 +46,9 @@ import com.android.wm.shell.pip.phone.PhonePipMenuController; import com.android.wm.shell.pip.phone.PipAppOpsListener; import com.android.wm.shell.pip.phone.PipController; import com.android.wm.shell.pip.phone.PipTouchHandler; +import com.android.wm.shell.transition.Transitions; import java.util.Optional; -import java.util.concurrent.Executor; import dagger.Module; import dagger.Provides; diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java index 6978ef4fb9ac..4e4c33a27da8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java @@ -37,13 +37,14 @@ import android.view.accessibility.IRemoteMagnificationAnimationCallback; import android.view.animation.AccelerateInterpolator; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.MediumTest; +import androidx.test.filters.LargeTest; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.systemui.SysuiTestCase; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -54,7 +55,8 @@ import org.mockito.MockitoAnnotations; import java.util.concurrent.atomic.AtomicReference; -@MediumTest +@Ignore +@LargeTest @RunWith(AndroidTestingRunner.class) public class WindowMagnificationAnimationControllerTest extends SysuiTestCase { diff --git a/services/Android.bp b/services/Android.bp index b51e4b014b27..da24719c0f68 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -30,6 +30,7 @@ filegroup { ":services.searchui-sources", ":services.startop.iorap-sources", ":services.systemcaptions-sources", + ":services.translation-sources", ":services.usage-sources", ":services.usb-sources", ":services.voiceinteraction-sources", @@ -76,6 +77,7 @@ java_library { "services.searchui", "services.startop", "services.systemcaptions", + "services.translation", "services.usage", "services.usb", "services.voiceinteraction", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 397eeb23396c..020c17a77084 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -620,7 +620,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private LingerMonitor mLingerMonitor; // sequence number of NetworkRequests - private int mNextNetworkRequestId = 1; + private int mNextNetworkRequestId = NetworkRequest.FIRST_REQUEST_ID; // Sequence number for NetworkProvider IDs. private final AtomicInteger mNextNetworkProviderId = new AtomicInteger( @@ -1238,6 +1238,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } private synchronized int nextNetworkRequestId() { + // TODO: Consider handle wrapping and exclude {@link NetworkRequest#REQUEST_ID_NONE} if + // doing that. return mNextNetworkRequestId++; } @@ -1329,15 +1331,20 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Check if UID should be blocked from using the specified network. */ - private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid, - boolean ignoreBlocked) { + private boolean isNetworkWithCapabilitiesBlocked(@Nullable final NetworkCapabilities nc, + final int uid, final boolean ignoreBlocked) { // Networks aren't blocked when ignoring blocked status if (ignoreBlocked) { return false; } if (isUidBlockedByVpn(uid, mVpnBlockedUidRanges)) return true; - final String iface = (lp == null ? "" : lp.getInterfaceName()); - return mPolicyManagerInternal.isUidNetworkingBlocked(uid, iface); + final long ident = Binder.clearCallingIdentity(); + try { + final boolean metered = nc == null ? true : nc.isMetered(); + return mPolicyManager.isUidNetworkingBlocked(uid, metered); + } finally { + Binder.restoreCallingIdentity(ident); + } } private void maybeLogBlockedNetworkInfo(NetworkInfo ni, int uid) { @@ -1375,12 +1382,13 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Apply any relevant filters to {@link NetworkState} for the given UID. For * example, this may mark the network as {@link DetailedState#BLOCKED} based - * on {@link #isNetworkWithLinkPropertiesBlocked}. + * on {@link #isNetworkWithCapabilitiesBlocked}. */ private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; - if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) { + if (isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, + ignoreBlocked)) { state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); } synchronized (mVpns) { @@ -1440,8 +1448,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } } nai = getDefaultNetwork(); - if (nai != null - && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) { + if (nai != null && isNetworkWithCapabilitiesBlocked( + nai.networkCapabilities, uid, ignoreBlocked)) { nai = null; } return nai != null ? nai.network : null; @@ -1513,7 +1521,7 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); final int uid = mDeps.getCallingUid(); NetworkState state = getFilteredNetworkState(networkType, uid); - if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) { + if (!isNetworkWithCapabilitiesBlocked(state.networkCapabilities, uid, false)) { return state.network; } return null; @@ -4471,7 +4479,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!nai.everConnected) { return; } - if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) { + final NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai); + if (isNetworkWithCapabilitiesBlocked(nc, uid, false)) { return; } nai.networkMonitor().forceReevaluation(uid); @@ -7065,11 +7074,11 @@ public class ConnectivityService extends IConnectivityManager.Stub log(" accepting network in place of " + previousSatisfier.toShortString()); } previousSatisfier.removeRequest(nri.request.requestId); - previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs); + previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs); } else { if (VDBG || DDBG) log(" accepting network in place of null"); } - newSatisfier.unlingerRequest(nri.request); + newSatisfier.unlingerRequest(nri.request.requestId); if (!newSatisfier.addRequest(nri.request)) { Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has " + nri.request); diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 99a1d86d244e..8b506bac4a85 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -54,9 +54,13 @@ import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; +import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; @@ -149,6 +153,11 @@ public class PackageWatchdog { private static final String ATTR_PASSED_HEALTH_CHECK = "passed-health-check"; private static final String ATTR_MITIGATION_CALLS = "mitigation-calls"; + // A file containing information about the current mitigation count in the case of a boot loop. + // This allows boot loop information to persist in the case of an fs-checkpoint being + // aborted. + private static final String METADATA_FILE = "/metadata/watchdog/mitigation_count.txt"; + @GuardedBy("PackageWatchdog.class") private static PackageWatchdog sPackageWatchdog; @@ -492,6 +501,7 @@ public class PackageWatchdog { } if (currentObserverToNotify != null) { mBootThreshold.setMitigationCount(mitigationCount); + mBootThreshold.saveMitigationCountToMetadata(); currentObserverToNotify.executeBootLoopMitigation(mitigationCount); } } @@ -1700,9 +1710,31 @@ public class PackageWatchdog { SystemProperties.set(property, Long.toString(newStart)); } + public void saveMitigationCountToMetadata() { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(METADATA_FILE))) { + writer.write(String.valueOf(getMitigationCount())); + } catch (Exception e) { + Slog.e(TAG, "Could not save metadata to file: " + e); + } + } + + public void readMitigationCountFromMetadataIfNecessary() { + File bootPropsFile = new File(METADATA_FILE); + if (bootPropsFile.exists()) { + try (BufferedReader reader = new BufferedReader(new FileReader(METADATA_FILE))) { + String mitigationCount = reader.readLine(); + setMitigationCount(Integer.parseInt(mitigationCount)); + bootPropsFile.delete(); + } catch (Exception e) { + Slog.i(TAG, "Could not read metadata file: " + e); + } + } + } + /** Increments the boot counter, and returns whether the device is bootlooping. */ public boolean incrementAndTest() { + readMitigationCountFromMetadataIfNecessary(); final long now = mSystemClock.uptimeMillis(); if (now - getStart() < 0) { Slog.e(TAG, "Window was less than zero. Resetting start to current time."); diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java index a1cf8162f0e9..db36e62e44a3 100644 --- a/services/core/java/com/android/server/RescueParty.java +++ b/services/core/java/com/android/server/RescueParty.java @@ -31,6 +31,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; +import android.os.PowerManager; import android.os.RecoverySystem; import android.os.RemoteCallback; import android.os.SystemClock; @@ -77,6 +78,7 @@ public class RescueParty { @VisibleForTesting static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue"; static final String PROP_ATTEMPTING_FACTORY_RESET = "sys.attempting_factory_reset"; + static final String PROP_ATTEMPTING_REBOOT = "sys.attempting_reboot"; static final String PROP_MAX_RESCUE_LEVEL_ATTEMPTED = "sys.max_rescue_level_attempted"; @VisibleForTesting static final int LEVEL_NONE = 0; @@ -87,7 +89,9 @@ public class RescueParty { @VisibleForTesting static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3; @VisibleForTesting - static final int LEVEL_FACTORY_RESET = 4; + static final int LEVEL_WARM_REBOOT = 4; + @VisibleForTesting + static final int LEVEL_FACTORY_RESET = 5; @VisibleForTesting static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count"; @VisibleForTesting @@ -159,12 +163,24 @@ public class RescueParty { } /** - * Check if we're currently attempting to reboot for a factory reset. + * Check if we're currently attempting to reboot for a factory reset. This method must + * return true if RescueParty tries to reboot early during a boot loop, since the device + * will not be fully booted at this time. + * + * TODO(gavincorkery): Rename method since its scope has expanded. */ public static boolean isAttemptingFactoryReset() { + return isFactoryResetPropertySet() || isRebootPropertySet(); + } + + static boolean isFactoryResetPropertySet() { return SystemProperties.getBoolean(PROP_ATTEMPTING_FACTORY_RESET, false); } + static boolean isRebootPropertySet() { + return SystemProperties.getBoolean(PROP_ATTEMPTING_REBOOT, false); + } + /** * Called when {@code SettingsProvider} has been published, which is a good * opportunity to reset any settings depending on our rescue level. @@ -329,8 +345,10 @@ public class RescueParty { return LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES; } else if (mitigationCount == 3) { return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS; - } else if (mitigationCount >= 4) { - return getMaxRescueLevel(); + } else if (mitigationCount == 4) { + return Math.min(getMaxRescueLevel(), LEVEL_WARM_REBOOT); + } else if (mitigationCount >= 5) { + return Math.min(getMaxRescueLevel(), LEVEL_FACTORY_RESET); } else { Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount); return LEVEL_NONE; @@ -356,6 +374,8 @@ public class RescueParty { // Try our best to reset all settings possible, and once finished // rethrow any exception that we encountered Exception res = null; + Runnable runnable; + Thread thread; switch (level) { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: try { @@ -396,11 +416,26 @@ public class RescueParty { res = e; } break; - case LEVEL_FACTORY_RESET: + case LEVEL_WARM_REBOOT: // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog // when device shutting down. + SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true"); + runnable = () -> { + try { + PowerManager pm = context.getSystemService(PowerManager.class); + if (pm != null) { + pm.reboot(TAG); + } + } catch (Throwable t) { + logRescueException(level, t); + } + }; + thread = new Thread(runnable); + thread.start(); + break; + case LEVEL_FACTORY_RESET: SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true"); - Runnable runnable = new Runnable() { + runnable = new Runnable() { @Override public void run() { try { @@ -410,7 +445,7 @@ public class RescueParty { } } }; - Thread thread = new Thread(runnable); + thread = new Thread(runnable); thread.start(); break; } @@ -433,6 +468,7 @@ public class RescueParty { case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return PackageHealthObserverImpact.USER_IMPACT_LOW; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: + case LEVEL_WARM_REBOOT: case LEVEL_FACTORY_RESET: return PackageHealthObserverImpact.USER_IMPACT_HIGH; default: @@ -714,6 +750,7 @@ public class RescueParty { case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: return "RESET_SETTINGS_UNTRUSTED_DEFAULTS"; case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: return "RESET_SETTINGS_UNTRUSTED_CHANGES"; case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: return "RESET_SETTINGS_TRUSTED_DEFAULTS"; + case LEVEL_WARM_REBOOT: return "WARM_REBOOT"; case LEVEL_FACTORY_RESET: return "FACTORY_RESET"; default: return Integer.toString(level); } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index b0f2e24e3be2..c951fd438b78 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1716,7 +1716,7 @@ class StorageManagerService extends IStorageManager.Stub public StorageManagerService(Context context) { sSelf = this; mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( - ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mContext = context; mResolver = mContext.getContentResolver(); mCallbacks = new Callbacks(FgThread.get().getLooper()); diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 53d75d1ddd06..6f6cad043a42 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -711,7 +711,7 @@ public final class ProcessList { mAppDataIsolationEnabled = SystemProperties.getBoolean(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); mVoldAppDataIsolationEnabled = SystemProperties.getBoolean( - ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, true); + ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false); mAppDataIsolationWhitelistedApps = new ArrayList<>( SystemConfig.getInstance().getAppDataIsolationWhitelistedApps()); diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index 18907a19f96d..9ba957ef27ae 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -64,7 +64,7 @@ public final class CompatChange extends CompatibilityChangeInfo { private Map<String, Boolean> mDeferredOverrides; public CompatChange(long changeId) { - this(changeId, null, -1, -1, false, false, null); + this(changeId, null, -1, -1, false, false, null, false); } /** @@ -77,9 +77,10 @@ public final class CompatChange extends CompatibilityChangeInfo { * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set. */ public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk, - int enableSinceTargetSdk, boolean disabled, boolean loggingOnly, String description) { + int enableSinceTargetSdk, boolean disabled, boolean loggingOnly, String description, + boolean overridable) { super(changeId, name, enableAfterTargetSdk, enableSinceTargetSdk, disabled, loggingOnly, - description); + description, overridable); } /** @@ -88,7 +89,7 @@ public final class CompatChange extends CompatibilityChangeInfo { public CompatChange(Change change) { super(change.getId(), change.getName(), change.getEnableAfterTargetSdk(), change.getEnableSinceTargetSdk(), change.getDisabled(), change.getLoggingOnly(), - change.getDescription()); + change.getDescription(), change.getOverridable()); } void registerListener(ChangeListener listener) { @@ -274,6 +275,9 @@ public final class CompatChange extends CompatibilityChangeInfo { if (mDeferredOverrides != null && mDeferredOverrides.size() > 0) { sb.append("; deferredOverrides=").append(mDeferredOverrides); } + if (getOverridable()) { + sb.append("; overridable"); + } return sb.append(")").toString(); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 7bde4d5a2770..55d8279a92d0 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -202,28 +202,28 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // either the linger timeout expiring and the network being taken down, or the network // satisfying a request again. public static class LingerTimer implements Comparable<LingerTimer> { - public final NetworkRequest request; + public final int requestId; public final long expiryMs; - public LingerTimer(NetworkRequest request, long expiryMs) { - this.request = request; + public LingerTimer(int requestId, long expiryMs) { + this.requestId = requestId; this.expiryMs = expiryMs; } public boolean equals(Object o) { if (!(o instanceof LingerTimer)) return false; LingerTimer other = (LingerTimer) o; - return (request.requestId == other.request.requestId) && (expiryMs == other.expiryMs); + return (requestId == other.requestId) && (expiryMs == other.expiryMs); } public int hashCode() { - return Objects.hash(request.requestId, expiryMs); + return Objects.hash(requestId, expiryMs); } public int compareTo(LingerTimer other) { return (expiryMs != other.expiryMs) ? Long.compare(expiryMs, other.expiryMs) : - Integer.compare(request.requestId, other.request.requestId); + Integer.compare(requestId, other.requestId); } public String toString() { - return String.format("%s, expires %dms", request.toString(), + return String.format("%s, expires %dms", requestId, expiryMs - SystemClock.elapsedRealtime()); } } @@ -693,7 +693,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { updateRequestCounts(REMOVE, existing); mNetworkRequests.remove(requestId); if (existing.isRequest()) { - unlingerRequest(existing); + unlingerRequest(existing.requestId); } } @@ -839,33 +839,33 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } /** - * Sets the specified request to linger on this network for the specified time. Called by + * Sets the specified requestId to linger on this network for the specified time. Called by * ConnectivityService when the request is moved to another network with a higher score. */ - public void lingerRequest(NetworkRequest request, long now, long duration) { - if (mLingerTimerForRequest.get(request.requestId) != null) { + public void lingerRequest(int requestId, long now, long duration) { + if (mLingerTimerForRequest.get(requestId) != null) { // Cannot happen. Once a request is lingering on a particular network, we cannot // re-linger it unless that network becomes the best for that request again, in which // case we should have unlingered it. - Log.wtf(TAG, toShortString() + ": request " + request.requestId + " already lingered"); + Log.wtf(TAG, toShortString() + ": request " + requestId + " already lingered"); } final long expiryMs = now + duration; - LingerTimer timer = new LingerTimer(request, expiryMs); + LingerTimer timer = new LingerTimer(requestId, expiryMs); if (VDBG) Log.d(TAG, "Adding LingerTimer " + timer + " to " + toShortString()); mLingerTimers.add(timer); - mLingerTimerForRequest.put(request.requestId, timer); + mLingerTimerForRequest.put(requestId, timer); } /** * Cancel lingering. Called by ConnectivityService when a request is added to this network. - * Returns true if the given request was lingering on this network, false otherwise. + * Returns true if the given requestId was lingering on this network, false otherwise. */ - public boolean unlingerRequest(NetworkRequest request) { - LingerTimer timer = mLingerTimerForRequest.get(request.requestId); + public boolean unlingerRequest(int requestId) { + LingerTimer timer = mLingerTimerForRequest.get(requestId); if (timer != null) { if (VDBG) Log.d(TAG, "Removing LingerTimer " + timer + " from " + toShortString()); mLingerTimers.remove(timer); - mLingerTimerForRequest.remove(request.requestId); + mLingerTimerForRequest.remove(requestId); return true; } return false; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 07a4b89be4e9..b250f164a264 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1850,34 +1850,6 @@ public class Vpn { } } - /** - * @param uid The target uid. - * - * @return {@code true} if {@code uid} is included in one of the mBlockedUidsAsToldToNetd - * ranges and the VPN is not connected, or if the VPN is connected but does not apply to - * the {@code uid}. - * - * @apiNote This method don't check VPN lockdown status. - * @see #mBlockedUidsAsToldToConnectivity - */ - public synchronized boolean isBlockingUid(int uid) { - if (mNetworkInfo.isConnected()) { - return !appliesToUid(uid); - } else { - return containsUid(mBlockedUidsAsToldToConnectivity, uid); - } - } - - private boolean containsUid(Collection<UidRangeParcel> ranges, int uid) { - if (ranges == null) return false; - for (UidRangeParcel range : ranges) { - if (range.start <= uid && uid <= range.stop) { - return true; - } - } - return false; - } - private void updateAlwaysOnNotification(DetailedState networkState) { final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 407cedf38917..141fa6a17873 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -44,12 +44,6 @@ public abstract class NetworkPolicyManagerInternal { public abstract boolean isUidRestrictedOnMeteredNetworks(int uid); /** - * @return true if networking is blocked on the given interface for the given uid according - * to current networking policies. - */ - public abstract boolean isUidNetworkingBlocked(int uid, String ifname); - - /** * Figure out if networking is blocked for a given set of conditions. * * This is used by ConnectivityService via passing stale copies of conditions, so it must not diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 0e7b4b8c9c5e..7c17356fa3cc 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -5352,7 +5352,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) { final long startTime = mStatLogger.getTime(); - mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG); + enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK); final int uidRules; final boolean isBackgroundRestricted; synchronized (mUidRulesFirstLock) { @@ -5451,32 +5451,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED); } - /** - * @return true if networking is blocked on the given interface for the given uid according - * to current networking policies. - */ - @Override - public boolean isUidNetworkingBlocked(int uid, String ifname) { - final long startTime = mStatLogger.getTime(); - - final int uidRules; - final boolean isBackgroundRestricted; - synchronized (mUidRulesFirstLock) { - uidRules = mUidRules.get(uid, RULE_NONE); - isBackgroundRestricted = mRestrictBackground; - } - final boolean isNetworkMetered; - synchronized (mMeteredIfacesLock) { - isNetworkMetered = mMeteredIfaces.contains(ifname); - } - final boolean ret = isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered, - isBackgroundRestricted, mLogger); - - mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime); - - return ret; - } - @Override public void onTempPowerSaveWhitelistChange(int appId, boolean added) { synchronized (mUidRulesFirstLock) { diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 9088d7b481a5..d65661771a84 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -138,7 +138,6 @@ import com.android.internal.os.BackgroundThread; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BinderCallsStats.ExportedCallStat; -import com.android.internal.os.KernelCpuSpeedReader; import com.android.internal.os.KernelCpuThreadReader; import com.android.internal.os.KernelCpuThreadReaderDiff; import com.android.internal.os.KernelCpuThreadReaderSettingsObserver; @@ -301,8 +300,6 @@ public class StatsPullAtomService extends SystemService { @GuardedBy("mDiskIoLock") private StoragedUidIoStatsReader mStoragedUidIoStatsReader; - @GuardedBy("mCpuTimePerFreqLock") - private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; // Disables throttler on CPU time readers. @GuardedBy("mCpuTimePerUidLock") private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader; @@ -353,7 +350,6 @@ public class StatsPullAtomService extends SystemService { private final Object mDataBytesTransferLock = new Object(); private final Object mBluetoothBytesTransferLock = new Object(); private final Object mKernelWakelockLock = new Object(); - private final Object mCpuTimePerFreqLock = new Object(); private final Object mCpuTimePerUidLock = new Object(); private final Object mCpuTimePerUidFreqLock = new Object(); private final Object mCpuActiveTimeLock = new Object(); @@ -442,10 +438,6 @@ public class StatsPullAtomService extends SystemService { synchronized (mKernelWakelockLock) { return pullKernelWakelockLocked(atomTag, data); } - case FrameworkStatsLog.CPU_TIME_PER_FREQ: - synchronized (mCpuTimePerFreqLock) { - return pullCpuTimePerFreqLocked(atomTag, data); - } case FrameworkStatsLog.CPU_TIME_PER_UID: synchronized (mCpuTimePerUidLock) { return pullCpuTimePerUidLocked(atomTag, data); @@ -722,18 +714,6 @@ public class StatsPullAtomService extends SystemService { mKernelWakelockReader = new KernelWakelockReader(); mTmpWakelockStats = new KernelWakelockStats(); - // Initialize state for CPU_TIME_PER_FREQ atom - PowerProfile powerProfile = new PowerProfile(mContext); - final int numClusters = powerProfile.getNumCpuClusters(); - mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters]; - int firstCpuOfCluster = 0; - for (int i = 0; i < numClusters; i++) { - final int numSpeedSteps = powerProfile.getNumSpeedStepsInCpuCluster(i); - mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster, - numSpeedSteps); - firstCpuOfCluster += powerProfile.getNumCoresInCpuCluster(i); - } - // Used for CPU_TIME_PER_THREAD_FREQ mKernelCpuThreadReader = KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); @@ -793,7 +773,6 @@ public class StatsPullAtomService extends SystemService { mStatsCallbackImpl = new StatsPullAtomCallbackImpl(); registerBluetoothBytesTransfer(); registerKernelWakelock(); - registerCpuTimePerFreq(); registerCpuTimePerUid(); registerCpuCyclesPerUidCluster(); registerCpuTimePerUidFreq(); @@ -1465,32 +1444,6 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } - private void registerCpuTimePerFreq() { - int tagId = FrameworkStatsLog.CPU_TIME_PER_FREQ; - PullAtomMetadata metadata = new PullAtomMetadata.Builder() - .setAdditiveFields(new int[] {3}) - .build(); - mStatsManager.setPullAtomCallback( - tagId, - metadata, - DIRECT_EXECUTOR, - mStatsCallbackImpl - ); - } - - int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) { - for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { - long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); - if (clusterTimeMs != null) { - for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) { - pulledData.add(FrameworkStatsLog.buildStatsEvent( - atomTag, cluster, speed, clusterTimeMs[speed])); - } - } - } - return StatsManager.PULL_SUCCESS; - } - private void registerCpuTimePerUid() { int tagId = FrameworkStatsLog.CPU_TIME_PER_UID; PullAtomMetadata metadata = new PullAtomMetadata.Builder() diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index 865571e90338..d0c632350270 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -18,6 +18,8 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.ActivityManager; import android.app.time.ITimeZoneDetectorListener; import android.app.time.TimeZoneCapabilitiesAndConfig; import android.app.time.TimeZoneConfiguration; @@ -26,12 +28,14 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.content.Context; import android.location.LocationManager; +import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -163,9 +167,13 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @Override @NonNull public TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig() { + int userId = mCallerIdentityInjector.getCallingUserId(); + return getCapabilitiesAndConfig(userId); + } + + TimeZoneCapabilitiesAndConfig getCapabilitiesAndConfig(@UserIdInt int userId) { enforceManageTimeZoneDetectorPermission(); - int userId = mCallerIdentityInjector.getCallingUserId(); final long token = mCallerIdentityInjector.clearCallingIdentity(); try { ConfigurationInternal configurationInternal = @@ -178,13 +186,22 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @Override public boolean updateConfiguration(@NonNull TimeZoneConfiguration configuration) { + int callingUserId = mCallerIdentityInjector.getCallingUserId(); + return updateConfiguration(callingUserId, configuration); + } + + boolean updateConfiguration( + @UserIdInt int userId, @NonNull TimeZoneConfiguration configuration) { + userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + userId, false, false, "updateConfiguration", null); + enforceManageTimeZoneDetectorPermission(); + Objects.requireNonNull(configuration); - int callingUserId = mCallerIdentityInjector.getCallingUserId(); final long token = mCallerIdentityInjector.clearCallingIdentity(); try { - return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration); + return mTimeZoneDetectorStrategy.updateConfiguration(userId, configuration); } finally { mCallerIdentityInjector.restoreCallingIdentity(token); } @@ -318,11 +335,17 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub return isGeoLocationTimeZoneDetectionEnabled(mContext); } - boolean isLocationEnabled() { + boolean isLocationEnabled(@UserIdInt int userId) { enforceManageTimeZoneDetectorPermission(); - return mContext.getSystemService(LocationManager.class) - .isLocationEnabledForUser(mContext.getUser()); + final long token = mCallerIdentityInjector.clearCallingIdentity(); + try { + UserHandle user = UserHandle.of(userId); + LocationManager locationManager = mContext.getSystemService(LocationManager.class); + return locationManager.isLocationEnabledForUser(user); + } finally { + mCallerIdentityInjector.restoreCallingIdentity(token); + } } @Override diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index b2630300a6aa..e965f55e49d7 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -29,6 +29,7 @@ import android.app.time.TimeZoneConfiguration; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.os.ShellCommand; +import android.os.UserHandle; import java.io.PrintWriter; import java.util.function.Consumer; @@ -76,7 +77,8 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runIsAutoDetectionEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.getCapabilitiesAndConfig() + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.getCapabilitiesAndConfig(userId) .getConfiguration() .isAutoDetectionEnabled(); pw.println(enabled); @@ -92,14 +94,16 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runIsLocationEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.isLocationEnabled(); + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.isLocationEnabled(userId); pw.println(enabled); return 0; } private int runIsGeoDetectionEnabled() { final PrintWriter pw = getOutPrintWriter(); - boolean enabled = mInterface.getCapabilitiesAndConfig() + int userId = UserHandle.USER_CURRENT; + boolean enabled = mInterface.getCapabilitiesAndConfig(userId) .getConfiguration() .isGeoDetectionEnabled(); pw.println(enabled); @@ -108,18 +112,20 @@ class TimeZoneDetectorShellCommand extends ShellCommand { private int runSetAutoDetectionEnabled() { boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + int userId = UserHandle.USER_CURRENT; TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(enabled) .build(); - return mInterface.updateConfiguration(configuration) ? 0 : 1; + return mInterface.updateConfiguration(userId, configuration) ? 0 : 1; } private int runSetGeoDetectionEnabled() { boolean enabled = Boolean.parseBoolean(getNextArgRequired()); + int userId = UserHandle.USER_CURRENT; TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder() .setGeoDetectionEnabled(enabled) .build(); - return mInterface.updateConfiguration(configuration) ? 0 : 1; + return mInterface.updateConfiguration(userId, configuration) ? 0 : 1; } private int runSuggestGeolocationTimeZone() { diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index b0847879f456..03cf021d0e9b 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -174,6 +174,10 @@ class ActivityMetricsLogger { boolean allDrawn() { return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn(); } + + boolean contains(ActivityRecord r) { + return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r); + } } /** The information created when an activity is confirmed to be launched. */ @@ -793,6 +797,7 @@ class ActivityMetricsLogger { stopLaunchTrace(info); if (abort) { + mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity); launchObserverNotifyActivityLaunchCancelled(info); } else { if (info.isInterestingToLoggerAndObserver()) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 324e3acf8e73..a9c54741fcf6 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -5435,7 +5435,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final TransitionInfoSnapshot info = mTaskSupervisor .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); if (info != null) { - mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, + mTaskSupervisor.reportActivityLaunched(false /* timeout */, this, info.windowsFullyDrawnDelayMs, info.getLaunchState()); } } @@ -5476,9 +5476,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // so there is no valid info. But if it is the current top activity (e.g. sleeping), the // invalid state is still reported to make sure the waiting result is notified. if (validInfo || this == getDisplayArea().topRunningActivity()) { - mTaskSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, + mTaskSupervisor.reportActivityLaunched(false /* timeout */, this, windowsDrawnDelayMs, launchState); - mTaskSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs, launchState); } finishLaunchTickingLocked(); if (task != null) { diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 375c3e138a39..c6cc83b4c3bb 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -710,8 +710,12 @@ class ActivityStarter { // WaitResult. mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res, mLastStartActivityRecord, originalOptions); - return getExternalResult(mRequest.waitResult == null ? res - : waitForResult(res, mLastStartActivityRecord)); + if (mRequest.waitResult != null) { + mRequest.waitResult.result = res; + res = waitResultIfNeeded(mRequest.waitResult, mLastStartActivityRecord, + launchingState); + } + return getExternalResult(res); } } finally { onExecutionComplete(); @@ -796,48 +800,21 @@ class ActivityStarter { /** * Wait for activity launch completes. */ - private int waitForResult(int res, ActivityRecord r) { - mRequest.waitResult.result = res; - switch(res) { - case START_SUCCESS: { - mSupervisor.mWaitingActivityLaunched.add(mRequest.waitResult); - do { - try { - mService.mGlobalLock.wait(); - } catch (InterruptedException e) { - } - } while (mRequest.waitResult.result != START_TASK_TO_FRONT - && !mRequest.waitResult.timeout && mRequest.waitResult.who == null); - if (mRequest.waitResult.result == START_TASK_TO_FRONT) { - res = START_TASK_TO_FRONT; - } - break; - } - case START_DELIVERED_TO_TOP: { - mRequest.waitResult.timeout = false; - mRequest.waitResult.who = r.mActivityComponent; - mRequest.waitResult.totalTime = 0; - break; - } - case START_TASK_TO_FRONT: { - // ActivityRecord may represent a different activity, but it should not be - // in the resumed state. - if (r.nowVisible && r.isState(RESUMED)) { - mRequest.waitResult.timeout = false; - mRequest.waitResult.who = r.mActivityComponent; - mRequest.waitResult.totalTime = 0; - } else { - mSupervisor.waitActivityVisible(r.mActivityComponent, mRequest.waitResult); - // Note: the timeout variable is not currently not ever set. - do { - try { - mService.mGlobalLock.wait(); - } catch (InterruptedException e) { - } - } while (!mRequest.waitResult.timeout && mRequest.waitResult.who == null); - } - break; - } + private int waitResultIfNeeded(WaitResult waitResult, ActivityRecord r, + LaunchingState launchingState) { + final int res = waitResult.result; + if (res == START_DELIVERED_TO_TOP + || (res == START_TASK_TO_FRONT && r.nowVisible && r.isState(RESUMED))) { + // The activity should already be visible, so nothing to wait. + waitResult.timeout = false; + waitResult.who = r.mActivityComponent; + waitResult.totalTime = 0; + return res; + } + mSupervisor.waitActivityVisibleOrLaunched(waitResult, r, launchingState); + if (res == START_SUCCESS && waitResult.result == START_TASK_TO_FRONT) { + // A trampoline activity is launched and it brings another existing activity to front. + return START_TASK_TO_FRONT; } return res; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 73a6efdb6799..599bf3748dd9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -266,11 +266,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { */ private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20); - /** List of processes waiting to find out when a specific activity becomes visible. */ - private final ArrayList<WaitInfo> mWaitingForActivityVisible = new ArrayList<>(); - - /** List of processes waiting to find out about the next launched activity. */ - final ArrayList<WaitResult> mWaitingActivityLaunched = new ArrayList<>(); + /** List of requests waiting for the target activity to be launched or visible. */ + private final ArrayList<WaitInfo> mWaitingActivityLaunched = new ArrayList<>(); /** List of activities that are ready to be stopped, but waiting for the next activity to * settle down before doing so. */ @@ -552,9 +549,21 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { return candidateTaskId; } - void waitActivityVisible(ComponentName name, WaitResult result) { - final WaitInfo waitInfo = new WaitInfo(name, result); - mWaitingForActivityVisible.add(waitInfo); + void waitActivityVisibleOrLaunched(WaitResult w, ActivityRecord r, + LaunchingState launchingState) { + if (w.result != ActivityManager.START_TASK_TO_FRONT + && w.result != ActivityManager.START_SUCCESS) { + // Not a result code that can make activity visible or launched. + return; + } + final WaitInfo waitInfo = new WaitInfo(w, r.mActivityComponent, launchingState); + mWaitingActivityLaunched.add(waitInfo); + do { + try { + mService.mGlobalLock.wait(); + } catch (InterruptedException ignored) { + } + } while (mWaitingActivityLaunched.contains(waitInfo)); } void cleanupActivity(ActivityRecord r) { @@ -568,23 +577,25 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** There is no valid launch time, just stop waiting. */ void stopWaitingForActivityVisible(ActivityRecord r) { - stopWaitingForActivityVisible(r, WaitResult.INVALID_DELAY, WaitResult.LAUNCH_STATE_UNKNOWN); + reportActivityLaunched(false /* timeout */, r, WaitResult.INVALID_DELAY, + WaitResult.LAUNCH_STATE_UNKNOWN); } - void stopWaitingForActivityVisible(ActivityRecord r, long totalTime, + void reportActivityLaunched(boolean timeout, ActivityRecord r, long totalTime, @WaitResult.LaunchState int launchState) { boolean changed = false; - for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) { - final WaitInfo w = mWaitingForActivityVisible.get(i); - if (w.matches(r.mActivityComponent)) { - final WaitResult result = w.getResult(); - changed = true; - result.timeout = false; - result.who = w.getComponent(); - result.totalTime = totalTime; - result.launchState = launchState; - mWaitingForActivityVisible.remove(w); + for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { + final WaitInfo info = mWaitingActivityLaunched.get(i); + if (!info.matches(r)) { + continue; } + final WaitResult w = info.mResult; + w.timeout = timeout; + w.who = r.mActivityComponent; + w.totalTime = totalTime; + w.launchState = launchState; + mWaitingActivityLaunched.remove(i); + changed = true; } if (changed) { mService.mGlobalLock.notifyAll(); @@ -603,38 +614,18 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { boolean changed = false; for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { - WaitResult w = mWaitingActivityLaunched.remove(i); - if (w.who == null) { - changed = true; - w.result = result; - + final WaitInfo info = mWaitingActivityLaunched.get(i); + if (!info.matches(r)) { + continue; + } + final WaitResult w = info.mResult; + w.result = result; + if (result == START_DELIVERED_TO_TOP) { // Unlike START_TASK_TO_FRONT, When an intent is delivered to top, there // will be no followup launch signals. Assign the result and launched component. - if (result == START_DELIVERED_TO_TOP) { - w.who = r.mActivityComponent; - } - } - } - - if (changed) { - mService.mGlobalLock.notifyAll(); - } - } - - void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime, - @WaitResult.LaunchState int launchState) { - boolean changed = false; - for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { - WaitResult w = mWaitingActivityLaunched.remove(i); - if (w.who == null) { + w.who = r.mActivityComponent; + mWaitingActivityLaunched.remove(i); changed = true; - w.timeout = timeout; - if (r != null) { - w.who = new ComponentName(r.info.packageName, r.info.name); - } - w.totalTime = totalTime; - w.launchState = launchState; - // Do not modify w.result. } } if (changed) { @@ -1295,8 +1286,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); if (fromTimeout) { - reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY, - -1 /* launchState */); + reportActivityLaunched(fromTimeout, r, INVALID_DELAY, -1 /* launchState */); } // This is a hack to semi-deal with a race condition @@ -1940,14 +1930,14 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser); pw.println(prefix + "mUserRootTaskInFront=" + mRootWindowContainer.mUserRootTaskInFront); pw.println(prefix + "mVisibilityTransactionDepth=" + mVisibilityTransactionDepth); - if (!mWaitingForActivityVisible.isEmpty()) { - pw.println(prefix + "mWaitingForActivityVisible="); - for (int i = 0; i < mWaitingForActivityVisible.size(); ++i) { - pw.print(prefix + prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix); - } - } pw.print(prefix); pw.print("isHomeRecentsComponent="); pw.println(mRecentTasks.isRecentsComponentHomeActivity(mRootWindowContainer.mCurrentUser)); + if (!mWaitingActivityLaunched.isEmpty()) { + pw.println(prefix + "mWaitingActivityLaunched="); + for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { + mWaitingActivityLaunched.get(i).dump(pw, prefix + " "); + } + } pw.println(); } @@ -2604,32 +2594,30 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { /** * Internal container to store a match qualifier alongside a WaitResult. */ - static class WaitInfo { - private final ComponentName mTargetComponent; - private final WaitResult mResult; - - WaitInfo(ComponentName targetComponent, WaitResult result) { - this.mTargetComponent = targetComponent; - this.mResult = result; - } - - public boolean matches(ComponentName targetComponent) { - return mTargetComponent == null || mTargetComponent.equals(targetComponent); - } + private static class WaitInfo { + final WaitResult mResult; + final ComponentName mTargetComponent; + /** + * The target component may not be the final drawn activity. The launching state is managed + * by {@link ActivityMetricsLogger} that can track consecutive launching sequence. + */ + final LaunchingState mLaunchingState; - public WaitResult getResult() { - return mResult; + WaitInfo(WaitResult result, ComponentName component, LaunchingState launchingState) { + mResult = result; + mTargetComponent = component; + mLaunchingState = launchingState; } - public ComponentName getComponent() { - return mTargetComponent; + boolean matches(ActivityRecord r) { + return mTargetComponent.equals(r.mActivityComponent) || mLaunchingState.contains(r); } - public void dump(PrintWriter pw, String prefix) { + void dump(PrintWriter pw, String prefix) { pw.println(prefix + "WaitInfo:"); pw.println(prefix + " mTargetComponent=" + mTargetComponent); pw.println(prefix + " mResult="); - mResult.dump(pw, prefix); + mResult.dump(pw, prefix + " "); } } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 61410f82835e..a88e4537d1a2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -5438,14 +5438,6 @@ class Task extends WindowContainer<WindowContainer> { r.completeResumeLocked(); } - private void clearLaunchTime(ActivityRecord r) { - // Make sure that there is no activity waiting for this to launch. - if (!mTaskSupervisor.mWaitingActivityLaunched.isEmpty()) { - mTaskSupervisor.removeIdleTimeoutForActivity(r); - mTaskSupervisor.scheduleIdleTimeout(r); - } - } - void awakeFromSleepingLocked() { if (!isLeafTask()) { forAllLeafTasks((task) -> task.awakeFromSleepingLocked(), @@ -5588,7 +5580,6 @@ class Task extends WindowContainer<WindowContainer> { mLastNoHistoryActivity = prev.isNoHistory() ? prev : null; prev.setState(PAUSING, "startPausingLocked"); prev.getTask().touchActiveTime(); - clearLaunchTime(prev); mAtmService.updateCpuStats(); diff --git a/services/core/xsd/platform-compat-config.xsd b/services/core/xsd/platform-compat-config.xsd index 992470816068..a62e2c385766 100644 --- a/services/core/xsd/platform-compat-config.xsd +++ b/services/core/xsd/platform-compat-config.xsd @@ -31,6 +31,7 @@ <xs:attribute type="xs:int" name="enableAfterTargetSdk"/> <xs:attribute type="xs:int" name="enableSinceTargetSdk"/> <xs:attribute type="xs:string" name="description"/> + <xs:attribute type="xs:boolean" name="overridable"/> </xs:extension> </xs:simpleContent> </xs:complexType> @@ -48,7 +49,3 @@ </xs:unique> </xs:element> </xs:schema> - - - - diff --git a/services/core/xsd/platform-compat-schema/current.txt b/services/core/xsd/platform-compat-schema/current.txt index e3640edd0201..fb8bbefd8374 100644 --- a/services/core/xsd/platform-compat-schema/current.txt +++ b/services/core/xsd/platform-compat-schema/current.txt @@ -10,6 +10,7 @@ package com.android.server.compat.config { method public long getId(); method public boolean getLoggingOnly(); method public String getName(); + method public boolean getOverridable(); method public String getValue(); method public void setDescription(String); method public void setDisabled(boolean); @@ -18,6 +19,7 @@ package com.android.server.compat.config { method public void setId(long); method public void setLoggingOnly(boolean); method public void setName(String); + method public void setOverridable(boolean); method public void setValue(String); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java index a281180d77d1..48f8b1505d3a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -134,6 +134,8 @@ class ActiveAdmin { private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; private static final String TAG_PASSWORD_COMPLEXITY = "password-complexity"; + private static final String TAG_ORGANIZATION_ID = "organization-id"; + private static final String TAG_ENROLLMENT_SPECIFIC_ID = "enrollment-specific-id"; private static final String ATTR_VALUE = "value"; private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; @@ -273,6 +275,8 @@ class ActiveAdmin { public String mAlwaysOnVpnPackage; public boolean mAlwaysOnVpnLockdown; boolean mCommonCriteriaMode; + public String mOrganizationId; + public String mEnrollmentSpecificId; ActiveAdmin(DeviceAdminInfo info, boolean isParent) { this.info = info; @@ -533,6 +537,12 @@ class ActiveAdmin { if (mPasswordComplexity != PASSWORD_COMPLEXITY_NONE) { writeAttributeValueToXml(out, TAG_PASSWORD_COMPLEXITY, mPasswordComplexity); } + if (!TextUtils.isEmpty(mOrganizationId)) { + writeTextToXml(out, TAG_ORGANIZATION_ID, mOrganizationId); + } + if (!TextUtils.isEmpty(mEnrollmentSpecificId)) { + writeTextToXml(out, TAG_ENROLLMENT_SPECIFIC_ID, mEnrollmentSpecificId); + } } void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException { @@ -766,6 +776,22 @@ class ActiveAdmin { mCommonCriteriaMode = parser.getAttributeBoolean(null, ATTR_VALUE, false); } else if (TAG_PASSWORD_COMPLEXITY.equals(tag)) { mPasswordComplexity = parser.getAttributeInt(null, ATTR_VALUE); + } else if (TAG_ORGANIZATION_ID.equals(tag)) { + type = parser.next(); + if (type == TypedXmlPullParser.TEXT) { + mOrganizationId = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing Organization ID."); + } + } else if (TAG_ENROLLMENT_SPECIFIC_ID.equals(tag)) { + type = parser.next(); + if (type == TypedXmlPullParser.TEXT) { + mEnrollmentSpecificId = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing Enrollment-specific ID."); + } } else { Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -1107,5 +1133,15 @@ class ActiveAdmin { pw.print("mPasswordComplexity="); pw.println(mPasswordComplexity); + + if (!TextUtils.isEmpty(mOrganizationId)) { + pw.print("mOrganizationId="); + pw.println(mOrganizationId); + } + + if (!TextUtils.isEmpty(mEnrollmentSpecificId)) { + pw.print("mEnrollmentSpecificId="); + pw.println(mEnrollmentSpecificId); + } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 6f1d451e7224..22e9725f49ab 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -15,6 +15,7 @@ */ package com.android.server.devicepolicy; +import android.annotation.NonNull; import android.app.admin.DevicePolicySafetyChecker; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; @@ -101,4 +102,11 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public boolean canProfileOwnerResetPasswordWhenLocked(int userId) { return false; } + + public String getEnrollmentSpecificId() { + return ""; + } + + public void setOrganizationIdForUser( + @NonNull String callerPackage, @NonNull String enterpriseId, int userId) {} } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 3e51b7506dff..4654fca250a3 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -819,6 +819,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { handlePackagesChanged(intent.getData().getSchemeSpecificPart(), userHandle); + removeCredentialManagementApp(intent.getData().getSchemeSpecificPart()); } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)) { clearWipeProfileNotification(); } else if (Intent.ACTION_DATE_CHANGED.equals(action) @@ -949,6 +950,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private void removeCredentialManagementApp(String packageName) { + mBackgroundHandler.post(() -> { + try (KeyChainConnection connection = mInjector.keyChainBind()) { + IKeyChainService service = connection.getService(); + if (service.hasCredentialManagementApp() + && packageName.equals(service.getCredentialManagementAppPackageName())) { + service.removeCredentialManagementApp(); + } + } catch (RemoteException | InterruptedException | IllegalStateException e) { + Log.e(LOG_TAG, "Unable to remove the credential management app"); + } + }); + } + private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) { try { return targetPackage != null @@ -1419,6 +1434,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return SecurityLog.isLoggingEnabled(); } + KeyChainConnection keyChainBind() throws InterruptedException { + return KeyChain.bind(mContext); + } + KeyChainConnection keyChainBindAsUser(UserHandle user) throws InterruptedException { return KeyChain.bindAsUser(mContext, user); } @@ -15581,4 +15600,69 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } } + + @Override + public String getEnrollmentSpecificId() { + if (!mHasFeature) { + return ""; + } + + final CallerIdentity caller = getCallerIdentity(); + Preconditions.checkCallAuthorization( + isDeviceOwner(caller) || isProfileOwner(caller)); + + synchronized (getLockObject()) { + final ActiveAdmin requiredAdmin = getDeviceOrProfileOwnerAdminLocked( + caller.getUserId()); + final String esid = requiredAdmin.mEnrollmentSpecificId; + return esid != null ? esid : ""; + } + } + + @Override + public void setOrganizationIdForUser( + @NonNull String callerPackage, @NonNull String organizationId, int userId) { + if (!mHasFeature) { + return; + } + Objects.requireNonNull(callerPackage); + + final CallerIdentity caller = getCallerIdentity(callerPackage); + // Only the DPC can set this ID. + Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller), + "Only a Device Owner or Profile Owner may set the Enterprise ID."); + // Empty enterprise ID must not be provided in calls to this method. + Preconditions.checkArgument(!TextUtils.isEmpty(organizationId), + "Enterprise ID may not be empty."); + + Log.i(LOG_TAG, + String.format("Setting Enterprise ID to %s for user %d", organizationId, userId)); + + synchronized (getLockObject()) { + ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); + // As the caller is the system, it must specify the component name of the profile owner + // as a safety check. + Preconditions.checkCallAuthorization( + owner != null && owner.getUserHandle().getIdentifier() == userId, + String.format("The Profile Owner or Device Owner may only set the Enterprise ID" + + " on its own user, called on user %d but owner user is %d", userId, + owner.getUserHandle().getIdentifier())); + Preconditions.checkState( + TextUtils.isEmpty(owner.mOrganizationId) || owner.mOrganizationId.equals( + organizationId), + "The organization ID has been previously set to a different value and cannot " + + "be changed"); + final String dpcPackage = owner.info.getPackageName(); + mInjector.binderWithCleanCallingIdentity(() -> { + EnterpriseSpecificIdCalculator esidCalculator = + new EnterpriseSpecificIdCalculator(mContext); + + final String esid = esidCalculator.calculateEnterpriseId(dpcPackage, + organizationId); + owner.mOrganizationId = organizationId; + owner.mEnrollmentSpecificId = esid; + saveSettingsLocked(userId); + }); + } + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java new file mode 100644 index 000000000000..df7f3084aeb3 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import android.content.Context; +import android.content.pm.VerifierDeviceIdentity; +import android.net.wifi.WifiManager; +import android.os.Build; +import android.security.identity.Util; +import android.telephony.TelephonyManager; +import android.text.TextUtils; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; + +import java.nio.ByteBuffer; + +class EnterpriseSpecificIdCalculator { + private static final int PADDED_HW_ID_LENGTH = 16; + private static final int PADDED_PROFILE_OWNER_LENGTH = 64; + private static final int PADDED_ENTERPRISE_ID_LENGTH = 64; + private static final int ESID_LENGTH = 16; + + private final String mImei; + private final String mMeid; + private final String mSerialNumber; + private final String mMacAddress; + + @VisibleForTesting + EnterpriseSpecificIdCalculator(String imei, String meid, String serialNumber, + String macAddress) { + mImei = imei; + mMeid = meid; + mSerialNumber = serialNumber; + mMacAddress = macAddress; + } + + EnterpriseSpecificIdCalculator(Context context) { + TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class); + Preconditions.checkState(telephonyService != null, "Unable to access telephony service"); + mImei = telephonyService.getImei(0); + mMeid = telephonyService.getMeid(0); + mSerialNumber = Build.getSerial(); + WifiManager wifiManager = context.getSystemService(WifiManager.class); + Preconditions.checkState(wifiManager != null, "Unable to access WiFi service"); + final String[] macAddresses = wifiManager.getFactoryMacAddresses(); + if (macAddresses == null || macAddresses.length == 0) { + mMacAddress = ""; + } else { + mMacAddress = macAddresses[0]; + } + } + + private static String getPaddedTruncatedString(String input, int maxLength) { + final String paddedValue = String.format("%" + maxLength + "s", input); + return paddedValue.substring(0, maxLength); + } + + private static String getPaddedHardwareIdentifier(String hardwareIdentifier) { + if (hardwareIdentifier == null) { + hardwareIdentifier = ""; + } + return getPaddedTruncatedString(hardwareIdentifier, PADDED_HW_ID_LENGTH); + } + + String getPaddedImei() { + return getPaddedHardwareIdentifier(mImei); + } + + String getPaddedMeid() { + return getPaddedHardwareIdentifier(mMeid); + } + + String getPaddedSerialNumber() { + return getPaddedHardwareIdentifier(mSerialNumber); + } + + String getPaddedProfileOwnerName(String profileOwnerPackage) { + return getPaddedTruncatedString(profileOwnerPackage, PADDED_PROFILE_OWNER_LENGTH); + } + + String getPaddedEnterpriseId(String enterpriseId) { + return getPaddedTruncatedString(enterpriseId, PADDED_ENTERPRISE_ID_LENGTH); + } + + /** + * Calculates the ESID. + * @param profileOwnerPackage Package of the Device Policy Client that manages the device/ + * profile. May not be null. + * @param enterpriseIdString The identifier for the enterprise in which the device/profile is + * being enrolled. This parameter may not be empty, but may be null. + * If called with {@code null}, will calculate an ESID with empty + * Enterprise ID. + */ + public String calculateEnterpriseId(String profileOwnerPackage, String enterpriseIdString) { + Preconditions.checkArgument(!TextUtils.isEmpty(profileOwnerPackage), + "owner package must be specified."); + + Preconditions.checkArgument(enterpriseIdString == null || !enterpriseIdString.isEmpty(), + "enterprise ID must either be null or non-empty."); + + if (enterpriseIdString == null) { + enterpriseIdString = ""; + } + + final byte[] serialNumber = getPaddedSerialNumber().getBytes(); + final byte[] imei = getPaddedImei().getBytes(); + final byte[] meid = getPaddedMeid().getBytes(); + final byte[] macAddress = mMacAddress.getBytes(); + final int totalIdentifiersLength = serialNumber.length + imei.length + meid.length + + macAddress.length; + final ByteBuffer fixedIdentifiers = ByteBuffer.allocate(totalIdentifiersLength); + fixedIdentifiers.put(serialNumber); + fixedIdentifiers.put(imei); + fixedIdentifiers.put(meid); + fixedIdentifiers.put(macAddress); + + final byte[] dpcPackage = getPaddedProfileOwnerName(profileOwnerPackage).getBytes(); + final byte[] enterpriseId = getPaddedEnterpriseId(enterpriseIdString).getBytes(); + final ByteBuffer info = ByteBuffer.allocate(dpcPackage.length + enterpriseId.length); + info.put(dpcPackage); + info.put(enterpriseId); + final byte[] esidBytes = Util.computeHkdf("HMACSHA256", fixedIdentifiers.array(), null, + info.array(), ESID_LENGTH); + ByteBuffer esidByteBuffer = ByteBuffer.wrap(esidBytes); + + VerifierDeviceIdentity firstId = new VerifierDeviceIdentity(esidByteBuffer.getLong()); + VerifierDeviceIdentity secondId = new VerifierDeviceIdentity(esidByteBuffer.getLong()); + return firstId.toString() + secondId.toString(); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java index 3220dff553d3..a691a8d44e48 100644 --- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java @@ -313,29 +313,30 @@ public class AppStateTrackerTest { } } - private static final int NONE = 0; - private static final int ALARMS_ONLY = 1 << 0; - private static final int JOBS_ONLY = 1 << 1; - private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY; - - private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, - int restrictionTypes, boolean exemptFromBatterySaver) { - assertEquals(((restrictionTypes & JOBS_ONLY) != 0), - instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver)); - assertEquals(((restrictionTypes & ALARMS_ONLY) != 0), - instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver)); + private void areJobsRestricted(AppStateTrackerTestable instance, int[] uids, String[] packages, + boolean[] restricted, boolean exemption) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], + instance.areJobsRestricted(uids[i], packages[i], exemption)); + } } - private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName, - int restrictionTypes) { - areRestricted(instance, uid, packageName, restrictionTypes, - /*exemptFromBatterySaver=*/ false); + private void areAlarmsRestrictedByFAS(AppStateTrackerTestable instance, int[] uids, + String[] packages, boolean[] restricted) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], instance.areAlarmsRestricted(uids[i], packages[i])); + } } - private void areRestrictedWithExemption(AppStateTrackerTestable instance, - int uid, String packageName, int restrictionTypes) { - areRestricted(instance, uid, packageName, restrictionTypes, - /*exemptFromBatterySaver=*/ true); + private void areAlarmsRestrictedByBatterySaver(AppStateTrackerTestable instance, int[] uids, + String[] packages, boolean[] restricted) { + assertTrue(uids.length == packages.length && uids.length == restricted.length); + for (int i = 0; i < uids.length; i++) { + assertEquals(restricted[i], + instance.areAlarmsRestrictedByBatterySaver(uids[i], packages[i])); + } } @Test @@ -344,30 +345,42 @@ public class AppStateTrackerTest { callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}); mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); assertTrue(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); // Toggle the foreground state. - mPowerSaveMode = true; - mPowerSaveObserver.accept(getPowerSaveState()); assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); @@ -376,34 +389,65 @@ public class AppStateTrackerTest { mIUidObserver.onUidActive(UID_1); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}); + assertTrue(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidGone(UID_1, /*disable=*/ false); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); + assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); mIUidObserver.onUidActive(UID_1); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, true, true, false}); mIUidObserver.onUidIdle(UID_1, /*disable=*/ false); waitUntilMainHandlerDrain(); waitUntilMainHandlerDrain(); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); + assertFalse(instance.isUidActive(UID_1)); assertFalse(instance.isUidActive(UID_2)); @@ -416,11 +460,19 @@ public class AppStateTrackerTest { assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); setAppOps(UID_1, PACKAGE_1, true); setAppOps(UID_10_2, PACKAGE_2, true); @@ -429,24 +481,72 @@ public class AppStateTrackerTest { assertTrue(instance.isRunAnyInBackgroundAppOpsAllowed(UID_2, PACKAGE_2)); assertFalse(instance.isRunAnyInBackgroundAppOpsAllowed(UID_10_2, PACKAGE_2)); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); // Toggle power saver, should still be the same. mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); + mPowerSaveMode = false; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, false, false, true, false}); // Clear the app ops and update the exemption list. setAppOps(UID_1, PACKAGE_1, false); @@ -455,24 +555,41 @@ public class AppStateTrackerTest { mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, true, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, false}); instance.setPowerSaveExemptionListAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2}); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, true, true, false}, + false); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, true, true, true, true, false}); // Again, make sure toggling the global state doesn't change it. mPowerSaveMode = false; @@ -481,13 +598,18 @@ public class AppStateTrackerTest { mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_10_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_10_2, PACKAGE_2, ALARMS_ONLY); - areRestricted(instance, UID_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false, true, true, false}, + false); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_10_1, UID_2, UID_10_2, UID_3, UID_10_3, Process.SYSTEM_UID}, + new String[]{PACKAGE_1, PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_3, PACKAGE_3, + PACKAGE_SYSTEM}, + new boolean[] {false, false, true, true, true, true, false}); assertTrue(instance.isUidPowerSaveExempt(UID_1)); assertTrue(instance.isUidPowerSaveExempt(UID_10_1)); @@ -646,52 +768,98 @@ public class AppStateTrackerTest { } @Test - public void testExempt() throws Exception { + public void testExemptedBucket() throws Exception { final AppStateTrackerTestable instance = newInstance(); callStart(instance); assertFalse(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + + areJobsRestricted(instance, + new int[] {UID_1, UID_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false}, + false); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false}); mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); assertTrue(instance.isForceAllAppsStandbyEnabled()); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {false, false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2, Process.SYSTEM_UID}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2, PACKAGE_SYSTEM}, + new boolean[] {true, true, true, false}); // Exempt package 2 on user-10. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, NONE); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); - areRestrictedWithExemption(instance, UID_10_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, true, false}); // Exempt package 1 on user-0. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_1, /*user=*/ 0, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, false}); // Unexempt package 2 on user-10. mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 10, false, UsageStatsManager.STANDBY_BUCKET_ACTIVE, REASON_MAIN_USAGE); - areRestricted(instance, UID_1, PACKAGE_1, NONE); - areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS); - areRestricted(instance, UID_10_2, PACKAGE_2, JOBS_AND_ALARMS); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, true}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}, + true); + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, true, true}); // Check force-app-standby. // EXEMPT doesn't exempt from force-app-standby. @@ -703,13 +871,28 @@ public class AppStateTrackerTest { mAppIdleStateChangeListener.onAppIdleStateChanged(PACKAGE_2, /*user=*/ 0, false, UsageStatsManager.STANDBY_BUCKET_EXEMPTED, REASON_MAIN_DEFAULT); + // All 3 packages (u0:p1, u0:p2, u10:p2) are now in the exempted bucket. setAppOps(UID_1, PACKAGE_1, true); - areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestricted(instance, UID_2, PACKAGE_2, NONE); - - areRestrictedWithExemption(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS); - areRestrictedWithExemption(instance, UID_2, PACKAGE_2, NONE); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}, + false); + areJobsRestricted(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}, + true); + + areAlarmsRestrictedByBatterySaver(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {false, false, false}); + areAlarmsRestrictedByFAS(instance, + new int[] {UID_1, UID_2, UID_10_2}, + new String[] {PACKAGE_1, PACKAGE_2, PACKAGE_2}, + new boolean[] {true, false, false}); } @Test @@ -809,6 +992,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -823,7 +1008,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -853,6 +1040,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -865,6 +1054,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(1)).unblockAlarmsForUidPackage(eq(UID_10_2), eq(PACKAGE_2)); @@ -876,15 +1067,16 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); - // Unrestrict while battery saver is on. Shouldn't fire. + // Test overlap with battery saver mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); - // Note toggling appops while BS is on will suppress unblockAlarmsForUidPackage(). setAppOps(UID_10_2, PACKAGE_2, true); waitUntilMainHandlerDrain(); @@ -892,6 +1084,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(1)).updateJobsForUidPackage(eq(UID_10_2), eq(PACKAGE_2), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -906,7 +1100,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -922,7 +1118,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(0)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(1)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -934,7 +1132,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -948,6 +1148,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -961,12 +1163,14 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); - // Do the same thing with battery saver on. (Currently same callbacks are called.) + // Do the same thing with battery saver on. mPowerSaveMode = true; mPowerSaveObserver.accept(getPowerSaveState()); @@ -975,6 +1179,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -989,7 +1195,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(0)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(1)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1001,7 +1209,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1015,6 +1225,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1028,6 +1240,8 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(anyInt(), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(anyInt()); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1037,9 +1251,8 @@ public class AppStateTrackerTest { // ------------------------------------------------------------------------- // Tests with proc state changes. - // With battery save. - mPowerSaveMode = true; - mPowerSaveObserver.accept(getPowerSaveState()); + // With battery saver. + // Battery saver is already on. mIUidObserver.onUidActive(UID_10_1); @@ -1049,6 +1262,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1062,6 +1277,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1075,6 +1292,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1088,12 +1307,14 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); - // Without battery save. + // Without battery saver. mPowerSaveMode = false; mPowerSaveObserver.accept(getPowerSaveState()); @@ -1102,7 +1323,9 @@ public class AppStateTrackerTest { verify(l, times(0)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); - verify(l, times(1)).unblockAllUnrestrictedAlarms(); + verify(l, times(1)).updateAllAlarms(); + verify(l, times(0)).updateAlarmsForUid(eq(UID_10_1)); + verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); reset(l); @@ -1115,6 +1338,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1128,6 +1353,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1141,6 +1368,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(1)).unblockAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); @@ -1154,6 +1383,8 @@ public class AppStateTrackerTest { verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean()); verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean()); + verify(l, times(0)).updateAllAlarms(); + verify(l, times(1)).updateAlarmsForUid(eq(UID_10_1)); verify(l, times(0)).unblockAllUnrestrictedAlarms(); verify(l, times(0)).unblockAlarmsForUid(anyInt()); verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString()); diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java index f375421043fd..fd364ae77240 100644 --- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java @@ -233,8 +233,10 @@ public class RescuePartyTest { verifiedTimesMap); noteBoot(4); + assertTrue(RescueParty.isRebootPropertySet()); - assertTrue(RescueParty.isAttemptingFactoryReset()); + noteBoot(5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -255,7 +257,10 @@ public class RescuePartyTest { /*configResetVerifiedTimesMap=*/ null); notePersistentAppCrash(4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + notePersistentAppCrash(5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -306,7 +311,11 @@ public class RescuePartyTest { observer.execute(new VersionedPackage( CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + observer.execute(new VersionedPackage( + CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -367,7 +376,11 @@ public class RescuePartyTest { observer.execute(new VersionedPackage( CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4); - assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isRebootPropertySet()); + + observer.execute(new VersionedPackage( + CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -376,6 +389,7 @@ public class RescuePartyTest { noteBoot(i + 1); } assertTrue(RescueParty.isAttemptingFactoryReset()); + assertTrue(RescueParty.isFactoryResetPropertySet()); } @Test @@ -424,7 +438,7 @@ public class RescuePartyTest { for (int i = 0; i < LEVEL_FACTORY_RESET; i++) { noteBoot(i + 1); } - assertFalse(RescueParty.isAttemptingFactoryReset()); + assertFalse(RescueParty.isFactoryResetPropertySet()); // Restore the property value initialized in SetUp() SystemProperties.set(PROP_DISABLE_FACTORY_RESET_FLAG, ""); diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 8edac4f8ce58..7a970a1c3d46 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -52,6 +52,7 @@ import static com.android.server.alarm.AlarmManagerService.Constants.KEY_LISTENE import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MAX_INTERVAL; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_FUTURITY; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_MIN_INTERVAL; +import static com.android.server.alarm.AlarmManagerService.INDEFINITE_DELAY; import static com.android.server.alarm.AlarmManagerService.IS_WAKEUP_MASK; import static com.android.server.alarm.AlarmManagerService.TIME_CHANGED_MASK; import static com.android.server.alarm.AlarmManagerService.WORKING_INDEX; @@ -71,6 +72,7 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; import android.app.ActivityManager; import android.app.ActivityManagerInternal; @@ -817,14 +819,14 @@ public class AlarmManagerServiceTest { } @Test - public void testAlarmRestrictedInBatterySaver() throws Exception { + public void testAlarmRestrictedByFAS() throws Exception { final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); final PendingIntent alarmPi = getNewMockPendingIntent(); - when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID, TEST_CALLING_PACKAGE, - false)).thenReturn(true); + when(mAppStateTracker.areAlarmsRestricted(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, alarmPi); assertEquals(mNowElapsedTest + 2, mTestTimer.getElapsed()); @@ -1301,7 +1303,6 @@ public class AlarmManagerServiceTest { final long awiDelayForTest = 23; setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, awiDelayForTest); - setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, 0); setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1000, getNewMockPendingIntent()); @@ -1336,7 +1337,7 @@ public class AlarmManagerServiceTest { } @Test - public void allowWhileIdleUnrestricted() throws Exception { + public void allowWhileIdleUnrestrictedInIdle() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); final long awiDelayForTest = 127; @@ -1361,7 +1362,7 @@ public class AlarmManagerServiceTest { } @Test - public void deviceIdleThrottling() throws Exception { + public void deviceIdleDeferralOnSet() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); final long deviceIdleUntil = mNowElapsedTest + 1234; @@ -1386,6 +1387,123 @@ public class AlarmManagerServiceTest { } @Test + public void deviceIdleStateChanges() throws Exception { + doReturn(0).when(mService).fuzzForDuration(anyLong()); + + final int numAlarms = 10; + final PendingIntent[] pis = new PendingIntent[numAlarms]; + for (int i = 0; i < numAlarms; i++) { + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i + 1, + pis[i] = getNewMockPendingIntent()); + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + } + + final PendingIntent idleUntil = getNewMockPendingIntent(); + setIdleUntilAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1234, idleUntil); + + assertEquals(mNowElapsedTest + 1234, mTestTimer.getElapsed()); + + mNowElapsedTest += 5; + mTestTimer.expire(); + // Nothing should happen. + verify(pis[0], never()).send(eq(mMockContext), eq(0), any(Intent.class), any(), + any(Handler.class), isNull(), any()); + + mService.removeLocked(idleUntil, null); + mTestTimer.expire(); + // Now, the first 5 alarms (upto i = 4) should expire. + for (int i = 0; i < 5; i++) { + verify(pis[i]).send(eq(mMockContext), eq(0), any(Intent.class), any(), + any(Handler.class), isNull(), any()); + } + // Rest should be restored, so the timer should reflect the next alarm. + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + } + + @Test + public void batterySaverThrottling() { + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); + verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); + final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue(); + + final PendingIntent alarmPi = getNewMockPendingIntent(); + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 7, alarmPi); + assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed()); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(false); + listener.updateAllAlarms(); + assertEquals(mNowElapsedTest + 7, mTestTimer.getElapsed()); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + listener.updateAlarmsForUid(TEST_CALLING_UID); + assertEquals(mNowElapsedTest + INDEFINITE_DELAY, mTestTimer.getElapsed()); + } + + @Test + public void allowWhileIdleAlarmsInBatterySaver() throws Exception { + final ArgumentCaptor<AppStateTrackerImpl.Listener> listenerArgumentCaptor = + ArgumentCaptor.forClass(AppStateTrackerImpl.Listener.class); + verify(mAppStateTracker).addListener(listenerArgumentCaptor.capture()); + final AppStateTrackerImpl.Listener listener = listenerArgumentCaptor.getValue(); + + final long longDelay = 23; + final long shortDelay = 7; + setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, longDelay); + setDeviceConfigLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, shortDelay); + + when(mAppStateTracker.areAlarmsRestrictedByBatterySaver(TEST_CALLING_UID, + TEST_CALLING_PACKAGE)).thenReturn(true); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), false); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 2, + getNewMockPendingIntent(), false); + + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + + mNowElapsedTest += 1; + mTestTimer.expire(); + + assertEquals(mNowElapsedTest + longDelay, mTestTimer.getElapsed()); + listener.onUidForeground(TEST_CALLING_UID, true); + // The next alarm should be deferred by shortDelay. + assertEquals(mNowElapsedTest + shortDelay, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), false); + + when(mAppStateTracker.isUidInForeground(TEST_CALLING_UID)).thenReturn(true); + mTestTimer.expire(); + // The next alarm should be deferred by shortDelay again. + assertEquals(mNowElapsedTest + shortDelay, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 1, + getNewMockPendingIntent(), true); + when(mAppStateTracker.isUidInForeground(TEST_CALLING_UID)).thenReturn(false); + mTestTimer.expire(); + final long lastAwiDispatch = mNowElapsedTest; + // Unrestricted, so should not be changed. + assertEquals(mNowElapsedTest + 1, mTestTimer.getElapsed()); + + mNowElapsedTest = mTestTimer.getElapsed(); + // AWI_unrestricted should not affect normal AWI bookkeeping. + // The next alarm is after the short delay but before the long delay. + setAllowWhileIdleAlarm(ELAPSED_REALTIME_WAKEUP, lastAwiDispatch + shortDelay + 1, + getNewMockPendingIntent(), false); + mTestTimer.expire(); + assertEquals(lastAwiDispatch + longDelay, mTestTimer.getElapsed()); + + listener.onUidForeground(TEST_CALLING_UID, true); + assertEquals(lastAwiDispatch + shortDelay + 1, mTestTimer.getElapsed()); + } + + @Test public void dispatchOrder() throws Exception { doReturn(0).when(mService).fuzzForDuration(anyLong()); diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index 4f4aa3f16f09..f00edcc85404 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -40,78 +40,83 @@ class CompatConfigBuilder { } CompatConfigBuilder addEnableAfterSdkChangeWithId(int sdk, long id) { - mChanges.add(new CompatChange(id, "", sdk, -1, false, false, "")); + mChanges.add(new CompatChange(id, "", sdk, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdAndName(int sdk, long id, String name) { - mChanges.add(new CompatChange(id, name, sdk, -1, false, false, "")); + mChanges.add(new CompatChange(id, name, sdk, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdDefaultDisabled(int sdk, long id) { - mChanges.add(new CompatChange(id, "", sdk, -1, true, false, "")); + mChanges.add(new CompatChange(id, "", sdk, -1, true, false, "", false)); return this; } CompatConfigBuilder addEnableAfterSdkChangeWithIdAndDescription(int sdk, long id, String description) { - mChanges.add(new CompatChange(id, "", sdk, -1, false, false, description)); + mChanges.add(new CompatChange(id, "", sdk, -1, false, false, description, false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithId(int sdk, long id) { - mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "")); + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdAndName(int sdk, long id, String name) { - mChanges.add(new CompatChange(id, name, -1, sdk, false, false, "")); + mChanges.add(new CompatChange(id, name, -1, sdk, false, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdDefaultDisabled(int sdk, long id) { - mChanges.add(new CompatChange(id, "", -1, sdk, true, false, "")); + mChanges.add(new CompatChange(id, "", -1, sdk, true, false, "", false)); return this; } CompatConfigBuilder addEnableSinceSdkChangeWithIdAndDescription(int sdk, long id, String description) { - mChanges.add(new CompatChange(id, "", -1, sdk, false, false, description)); + mChanges.add(new CompatChange(id, "", -1, sdk, false, false, description, false)); return this; } CompatConfigBuilder addEnabledChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, false, false, "")); + mChanges.add(new CompatChange(id, "", -1, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) { - mChanges.add(new CompatChange(id, name, -1, -1, false, false, "")); + mChanges.add(new CompatChange(id, name, -1, -1, false, false, "", false)); return this; } CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) { - mChanges.add(new CompatChange(id, "", -1, -1, false, false, description)); + mChanges.add(new CompatChange(id, "", -1, -1, false, false, description, false)); return this; } CompatConfigBuilder addDisabledChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, true, false, "")); + mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", false)); return this; } CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) { - mChanges.add(new CompatChange(id, name, -1, -1, true, false, "")); + mChanges.add(new CompatChange(id, name, -1, -1, true, false, "", false)); return this; } CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) { - mChanges.add(new CompatChange(id, "", -1, -1, true, false, description)); + mChanges.add(new CompatChange(id, "", -1, -1, true, false, description, false)); return this; } CompatConfigBuilder addLoggingOnlyChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, false, true, "")); + mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", false)); + return this; + } + + CompatConfigBuilder addOverridableChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", true)); return this; } diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index a70c51045340..a1b2dc8bd82d 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -97,17 +97,22 @@ public class PlatformCompatTest { .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.Q, 5L) .addEnableAfterSdkChangeWithId(Build.VERSION_CODES.R, 6L) .addLoggingOnlyChangeWithId(7L) + .addOverridableChangeWithId(8L) .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); assertThat(mPlatformCompat.listAllChanges()).asList().containsExactly( - new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""), - new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""), + new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), + new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), new CompatibilityChangeInfo(3L, "", Build.VERSION_CODES.O, -1, false, false, - "desc"), - new CompatibilityChangeInfo(4L, "", Build.VERSION_CODES.P, -1, false, false, ""), - new CompatibilityChangeInfo(5L, "", Build.VERSION_CODES.Q, -1, false, false, ""), - new CompatibilityChangeInfo(6L, "", Build.VERSION_CODES.R, -1, false, false, ""), - new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "")); + "desc", false), + new CompatibilityChangeInfo( + 4L, "", Build.VERSION_CODES.P, -1, false, false, "", false), + new CompatibilityChangeInfo( + 5L, "", Build.VERSION_CODES.Q, -1, false, false, "", false), + new CompatibilityChangeInfo( + 6L, "", Build.VERSION_CODES.R, -1, false, false, "", false), + new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "", false), + new CompatibilityChangeInfo(8L, "", -1, -1, false, true, "", true)); } @Test @@ -123,12 +128,12 @@ public class PlatformCompatTest { .build(); mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); assertThat(mPlatformCompat.listUIChanges()).asList().containsExactly( - new CompatibilityChangeInfo(1L, "", -1, -1, false, false, ""), - new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, ""), - new CompatibilityChangeInfo(5L, "", /*enableAfter*/ -1, - /*enableSince*/ Build.VERSION_CODES.Q, false, false, ""), - new CompatibilityChangeInfo(6L, "", /*enableAfter*/ -1, - /*enableSince*/ Build.VERSION_CODES.R, false, false, "")); + new CompatibilityChangeInfo(1L, "", -1, -1, false, false, "", false), + new CompatibilityChangeInfo(2L, "change2", -1, -1, true, false, "", false), + new CompatibilityChangeInfo( + 5L, "", Build.VERSION_CODES.P, -1, false, false, "", false), + new CompatibilityChangeInfo( + 6L, "", Build.VERSION_CODES.Q, -1, false, false, "", false)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 17324bab70d2..9c28c99fcc07 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -460,6 +460,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi } @Override + KeyChain.KeyChainConnection keyChainBind() { + return services.keyChainConnection; + } + + @Override KeyChain.KeyChainConnection keyChainBindAsUser(UserHandle user) { return services.keyChainConnection; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index c1b1133dbb22..39fa20e4153f 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1628,6 +1628,33 @@ public class DevicePolicyManagerTest extends DpmTestBase { )), eq(user)); } + @Test + public void testRemoveCredentialManagementApp() throws Exception { + final String packageName = "com.test.cred.mng"; + Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); + intent.setData(Uri.parse("package:" + packageName)); + dpms.mReceiver.setPendingResult( + new BroadcastReceiver.PendingResult(Activity.RESULT_OK, + "resultData", + /* resultExtras= */ null, + BroadcastReceiver.PendingResult.TYPE_UNREGISTERED, + /* ordered= */ true, + /* sticky= */ false, + /* token= */ null, + CALLER_USER_HANDLE, + /* flags= */ 0)); + when(getServices().keyChainConnection.getService().hasCredentialManagementApp()) + .thenReturn(true); + when(getServices().keyChainConnection.getService().getCredentialManagementAppPackageName()) + .thenReturn(packageName); + + dpms.mReceiver.onReceive(mContext, intent); + + flushTasks(dpms); + verify(getServices().keyChainConnection.getService()).hasCredentialManagementApp(); + verify(getServices().keyChainConnection.getService()).removeCredentialManagementApp(); + } + /** * Simple test for delegate set/get and general delegation. Tests verifying that delegated * privileges can acually be exercised by a delegate are not covered here. diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java new file mode 100644 index 000000000000..c2c1d5b4f3be --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/EnterpriseSpecificIdCalculatorTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import static com.google.common.truth.Truth.assertThat; + +import static org.testng.Assert.assertThrows; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class EnterpriseSpecificIdCalculatorTest { + private static final String SOME_IMEI = "56134231542345"; + private static final String SOME_SERIAL_NUMBER = "XZ663CCAJA7"; + private static final String SOME_MAC_ADDRESS = "65:ca:f3:fe:9d:b1"; + private static final String NO_MEID = null; + private static final String SOME_PACKAGE = "com.example.test.dpc"; + private static final String ANOTHER_PACKAGE = "org.example.test.another.dpc"; + private static final String SOME_ENTERPRISE_ID = "73456234"; + private static final String ANOTHER_ENTERPRISE_ID = "243441"; + + private EnterpriseSpecificIdCalculator mEsidCalculator; + + @Before + public void createDefaultEsidCalculator() { + mEsidCalculator = new EnterpriseSpecificIdCalculator(SOME_IMEI, NO_MEID, SOME_SERIAL_NUMBER, + SOME_MAC_ADDRESS); + } + + @Test + public void paddingOfIdentifiers() { + assertThat(mEsidCalculator.getPaddedImei()).isEqualTo(" 56134231542345"); + assertThat(mEsidCalculator.getPaddedMeid()).isEqualTo(" "); + assertThat(mEsidCalculator.getPaddedSerialNumber()).isEqualTo(" XZ663CCAJA7"); + } + + @Test + public void truncationOfLongIdentifier() { + EnterpriseSpecificIdCalculator esidCalculator = new EnterpriseSpecificIdCalculator( + SOME_IMEI, NO_MEID, "XZ663CCAJA7XZ663CCAJA7XZ663CCAJA7", + SOME_MAC_ADDRESS); + assertThat(esidCalculator.getPaddedSerialNumber()).isEqualTo("XZ663CCAJA7XZ663"); + } + + @Test + public void paddingOfPackageName() { + assertThat(mEsidCalculator.getPaddedProfileOwnerName(SOME_PACKAGE)).isEqualTo( + " " + SOME_PACKAGE); + } + + @Test + public void paddingOfEnterpriseId() { + assertThat(mEsidCalculator.getPaddedEnterpriseId(SOME_ENTERPRISE_ID)).isEqualTo( + " " + SOME_ENTERPRISE_ID); + } + + @Test + public void emptyEnterpriseIdYieldsEmptyEsid() { + assertThrows(IllegalArgumentException.class, () -> + mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, "")); + } + + @Test + public void emptyDpcPackageYieldsEmptyEsid() { + assertThrows(IllegalArgumentException.class, () -> + mEsidCalculator.calculateEnterpriseId("", SOME_ENTERPRISE_ID)); + } + + // On upgrade, an ESID will be calculated with an empty Enterprise ID. This is signalled + // to the EnterpriseSpecificIdCalculator by passing in null. + @Test + public void nullEnterpriseIdYieldsValidEsid() { + assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, null)).isEqualTo( + "C4W7-VUJT-PHSA-HMY53-CLHX-L4HW-L"); + } + + @Test + public void knownValues() { + assertThat( + mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, SOME_ENTERPRISE_ID)).isEqualTo( + "FP7B-RXQW-Q77F-7J6FC-5RXZ-UJI6-6"); + assertThat(mEsidCalculator.calculateEnterpriseId(SOME_PACKAGE, + ANOTHER_ENTERPRISE_ID)).isEqualTo("ATAL-VPIX-GBNZ-NE3TF-TDEV-3OVO-C"); + assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE, + SOME_ENTERPRISE_ID)).isEqualTo("JHU3-6SHH-YLHC-ZGETD-PWNI-7NPQ-S"); + assertThat(mEsidCalculator.calculateEnterpriseId(ANOTHER_PACKAGE, + ANOTHER_ENTERPRISE_ID)).isEqualTo("LEF3-QBEC-UQ6O-RIOCX-TQF6-GRLV-F"); + } +} diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java index 9c8a38219a9c..ac9316e7d908 100644 --- a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java @@ -24,6 +24,9 @@ import static org.junit.Assert.fail; import android.net.ConnectivityMetricsEvent; import android.net.IIpConnectivityMetrics; import android.net.INetdEventCallback; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -106,6 +109,16 @@ public class NetworkWatchlistServiceTests { counter--; return true; } + + // TODO: mark @Override when aosp/1541935 automerges to master. + public void logDefaultNetworkValidity(boolean valid) { + } + + // TODO: mark @Override when aosp/1541935 automerges to master. + public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated, + LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork, + int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) { + } }; ServiceThread mHandlerThread; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java index 475e462bdd3d..009c011105de 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java @@ -31,13 +31,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import android.app.WaitResult; +import android.content.ComponentName; import android.content.pm.ActivityInfo; +import android.os.ConditionVariable; import android.platform.test.annotations.Presubmit; import android.view.Display; @@ -58,6 +62,7 @@ import java.util.concurrent.TimeUnit; @Presubmit @RunWith(WindowTestRunner.class) public class ActivityTaskSupervisorTests extends WindowTestsBase { + private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); /** * Ensures that an activity is removed from the stopping activities list once it is resumed. @@ -74,30 +79,72 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { } /** - * Ensures that waiting results are notified of launches. + * Assume an activity has been started with result code START_SUCCESS. And before it is drawn, + * it launches another existing activity. This test ensures that waiting results are notified + * or updated while the result code of next launch is TASK_TO_FRONT or DELIVERED_TO_TOP. */ @Test - public void testReportWaitingActivityLaunchedIfNeeded() { + public void testReportWaitingActivityLaunched() { final ActivityRecord firstActivity = new ActivityBuilder(mAtm) .setCreateTask(true).build(); - + final ActivityRecord secondActivity = new ActivityBuilder(mAtm) + .setCreateTask(true).build(); + final ConditionVariable condition = new ConditionVariable(); final WaitResult taskToFrontWait = new WaitResult(); - mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait); - // #notifyAll will be called on the ActivityTaskManagerService#mGlobalLock. The lock is hold - // implicitly by WindowManagerGlobalLockRule. - mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT); - - assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); + final ComponentName[] launchedComponent = { null }; + // Create a new thread so the waiting method in test can be notified. + new Thread(() -> { + synchronized (mAtm.mGlobalLock) { + // Note that TASK_TO_FRONT doesn't unblock the waiting thread. + mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, + START_TASK_TO_FRONT); + launchedComponent[0] = taskToFrontWait.who; + // Assume that another task is brought to front because first activity launches it. + mSupervisor.reportActivityLaunched(false /* timeout */, secondActivity, + 100 /* totalTime */, WaitResult.LAUNCH_STATE_HOT); + } + condition.open(); + }).start(); + final ActivityMetricsLogger.LaunchingState launchingState = + new ActivityMetricsLogger.LaunchingState(); + spyOn(launchingState); + doReturn(true).when(launchingState).contains(eq(secondActivity)); + // The test case already runs inside global lock, so above thread can only execute after + // this waiting method that releases the lock. + mSupervisor.waitActivityVisibleOrLaunched(taskToFrontWait, firstActivity, launchingState); + + // Assert that the thread is finished. + assertTrue(condition.block(TIMEOUT_MS)); assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT); - assertNull(taskToFrontWait.who); + assertEquals(taskToFrontWait.who, secondActivity.mActivityComponent); + assertEquals(taskToFrontWait.launchState, WaitResult.LAUNCH_STATE_HOT); + // START_TASK_TO_FRONT means that another component will be visible, so the component + // should not be assigned as the first activity. + assertNull(launchedComponent[0]); + condition.close(); final WaitResult deliverToTopWait = new WaitResult(); - mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait); - mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP); - - assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty(); + new Thread(() -> { + synchronized (mAtm.mGlobalLock) { + // Put a noise which isn't tracked by the current wait result. The waiting procedure + // should ignore it and keep waiting for the target activity. + mSupervisor.reportActivityLaunched(false /* timeout */, mock(ActivityRecord.class), + 1000 /* totalTime */, WaitResult.LAUNCH_STATE_COLD); + // Assume that the first activity launches an existing top activity, so the waiting + // thread should be unblocked. + mSupervisor.reportWaitingActivityLaunchedIfNeeded(secondActivity, + START_DELIVERED_TO_TOP); + } + condition.open(); + }).start(); + mSupervisor.waitActivityVisibleOrLaunched(deliverToTopWait, firstActivity, launchingState); + + assertTrue(condition.block(TIMEOUT_MS)); assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP); - assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent); + assertEquals(deliverToTopWait.who, secondActivity.mActivityComponent); + // The result state must be unknown because DELIVERED_TO_TOP means that the target activity + // is already visible so there is no valid launch time. + assertEquals(deliverToTopWait.launchState, WaitResult.LAUNCH_STATE_UNKNOWN); } /** @@ -202,7 +249,6 @@ public class ActivityTaskSupervisorTests extends WindowTestsBase { public void testStartHomeAfterUserUnlocked() { mSupervisor.onUserUnlocked(0); waitHandlerIdle(mAtm.mH); - verify(mRootWindowContainer, timeout(TimeUnit.SECONDS.toMillis(10))) - .startHomeOnEmptyDisplays("userUnlocked"); + verify(mRootWindowContainer, timeout(TIMEOUT_MS)).startHomeOnEmptyDisplays("userUnlocked"); } } diff --git a/services/translation/Android.bp b/services/translation/Android.bp new file mode 100644 index 000000000000..804a6177e94e --- /dev/null +++ b/services/translation/Android.bp @@ -0,0 +1,13 @@ +filegroup { + name: "services.translation-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + +java_library_static { + name: "services.translation", + defaults: ["platform_service_defaults"], + srcs: [":services.translation-sources"], + libs: ["services.core"], +}
\ No newline at end of file diff --git a/services/translation/OWNERS b/services/translation/OWNERS new file mode 100644 index 000000000000..a1e663aa8ff7 --- /dev/null +++ b/services/translation/OWNERS @@ -0,0 +1,8 @@ +# Bug component: 994311 + +adamhe@google.com +augale@google.com +joannechung@google.com +lpeter@google.com +svetoslavganov@google.com +tymtsai@google.com diff --git a/services/translation/java/com/android/server/translation/RemoteTranslationService.java b/services/translation/java/com/android/server/translation/RemoteTranslationService.java new file mode 100644 index 000000000000..0c7e61765501 --- /dev/null +++ b/services/translation/java/com/android/server/translation/RemoteTranslationService.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.translation; + +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.service.translation.ITranslationService; +import android.service.translation.TranslationService; +import android.util.Slog; +import android.view.translation.TranslationSpec; + +import com.android.internal.infra.AbstractRemoteService; +import com.android.internal.infra.ServiceConnector; +import com.android.internal.os.IResultReceiver; + +final class RemoteTranslationService extends ServiceConnector.Impl<ITranslationService> { + + private static final String TAG = RemoteTranslationService.class.getSimpleName(); + + // TODO(b/176590870): Make PERMANENT now. + private static final long TIMEOUT_IDLE_UNBIND_MS = + AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS; + private static final int TIMEOUT_REQUEST_MS = 5_000; + + private final long mIdleUnbindTimeoutMs; + private final int mRequestTimeoutMs; + private final ComponentName mComponentName; + + RemoteTranslationService(Context context, ComponentName serviceName, + int userId, boolean bindInstantServiceAllowed) { + super(context, + new Intent(TranslationService.SERVICE_INTERFACE).setComponent(serviceName), + bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, + userId, ITranslationService.Stub::asInterface); + mIdleUnbindTimeoutMs = TIMEOUT_IDLE_UNBIND_MS; + mRequestTimeoutMs = TIMEOUT_REQUEST_MS; + mComponentName = serviceName; + + // Bind right away. + connect(); + } + + public ComponentName getComponentName() { + return mComponentName; + } + + @Override // from ServiceConnector.Impl + protected void onServiceConnectionStatusChanged(ITranslationService service, + boolean connected) { + try { + if (connected) { + service.onConnected(); + } else { + service.onDisconnected(); + } + } catch (Exception e) { + Slog.w(TAG, + "Exception calling onServiceConnectionStatusChanged(" + connected + "): ", e); + } + } + + @Override // from AbstractRemoteService + protected long getAutoDisconnectTimeoutMs() { + return mIdleUnbindTimeoutMs; + } + + public void onSessionCreated(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) { + run((s) -> s.onCreateTranslationSession(sourceSpec, destSpec, sessionId, resultReceiver)); + } +} diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java new file mode 100644 index 000000000000..e2aabe6a89ea --- /dev/null +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.translation; + +import static android.content.Context.TRANSLATION_MANAGER_SERVICE; +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; + +import android.content.Context; +import android.os.RemoteException; +import android.util.Slog; +import android.view.translation.ITranslationManager; +import android.view.translation.TranslationSpec; + +import com.android.internal.os.IResultReceiver; +import com.android.server.infra.AbstractMasterSystemService; +import com.android.server.infra.FrameworkResourcesServiceNameResolver; + +/** + * Entry point service for translation management. + * + * <p>This service provides the {@link ITranslationManager} implementation and keeps a list of + * {@link TranslationManagerServiceImpl} per user; the real work is done by + * {@link TranslationManagerServiceImpl} itself. + */ +public final class TranslationManagerService + extends AbstractMasterSystemService<TranslationManagerService, + TranslationManagerServiceImpl> { + + private static final String TAG = "TranslationManagerService"; + + public TranslationManagerService(Context context) { + // TODO: Discuss the disallow policy + super(context, new FrameworkResourcesServiceNameResolver(context, + com.android.internal.R.string.config_defaultTranslationService), + /* disallowProperty */ null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER); + } + + @Override + protected TranslationManagerServiceImpl newServiceLocked(int resolvedUserId, boolean disabled) { + return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled); + } + + final class TranslationManagerServiceStub extends ITranslationManager.Stub { + @Override + public void getSupportedLocales(IResultReceiver receiver, int userId) + throws RemoteException { + synchronized (mLock) { + final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.getSupportedLocalesLocked(receiver); + } else { + Slog.v(TAG, "getSupportedLocales(): no service for " + userId); + receiver.send(STATUS_SYNC_CALL_FAIL, null); + } + } + } + + @Override + public void onSessionCreated(TranslationSpec sourceSpec, TranslationSpec destSpec, + int sessionId, IResultReceiver receiver, int userId) throws RemoteException { + synchronized (mLock) { + final TranslationManagerServiceImpl service = getServiceForUserLocked(userId); + if (service != null) { + service.onSessionCreatedLocked(sourceSpec, destSpec, sessionId, receiver); + } else { + Slog.v(TAG, "onSessionCreated(): no service for " + userId); + receiver.send(STATUS_SYNC_CALL_FAIL, null); + } + } + } + } + + @Override // from SystemService + public void onStart() { + publishBinderService(TRANSLATION_MANAGER_SERVICE, + new TranslationManagerService.TranslationManagerServiceStub()); + } +} diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java new file mode 100644 index 000000000000..b1f6f80d4158 --- /dev/null +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.translation; + +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_SUCCESS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.os.RemoteException; +import android.service.translation.TranslationServiceInfo; +import android.util.Slog; +import android.view.translation.TranslationSpec; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.IResultReceiver; +import com.android.internal.util.SyncResultReceiver; +import com.android.server.infra.AbstractPerUserSystemService; + +import java.util.ArrayList; + +final class TranslationManagerServiceImpl extends + AbstractPerUserSystemService<TranslationManagerServiceImpl, TranslationManagerService> { + + private static final String TAG = "TranslationManagerServiceImpl"; + + @GuardedBy("mLock") + @Nullable + private RemoteTranslationService mRemoteTranslationService; + + @GuardedBy("mLock") + @Nullable + private ServiceInfo mRemoteTranslationServiceInfo; + + protected TranslationManagerServiceImpl( + @NonNull TranslationManagerService master, + @NonNull Object lock, int userId, boolean disabled) { + super(master, lock, userId); + updateRemoteServiceLocked(); + } + + @GuardedBy("mLock") + @Override // from PerUserSystemService + protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) + throws PackageManager.NameNotFoundException { + final TranslationServiceInfo info = new TranslationServiceInfo(getContext(), + serviceComponent, isTemporaryServiceSetLocked(), mUserId); + mRemoteTranslationServiceInfo = info.getServiceInfo(); + return info.getServiceInfo(); + } + + @GuardedBy("mLock") + @Override // from PerUserSystemService + protected boolean updateLocked(boolean disabled) { + final boolean enabledChanged = super.updateLocked(disabled); + updateRemoteServiceLocked(); + return enabledChanged; + } + + /** + * Updates the reference to the remote service. + */ + @GuardedBy("mLock") + private void updateRemoteServiceLocked() { + if (mRemoteTranslationService != null) { + if (mMaster.debug) Slog.d(TAG, "updateRemoteService(): destroying old remote service"); + mRemoteTranslationService.unbind(); + mRemoteTranslationService = null; + } + } + + @GuardedBy("mLock") + @Nullable + private RemoteTranslationService ensureRemoteServiceLocked() { + if (mRemoteTranslationService == null) { + final String serviceName = getComponentNameLocked(); + if (serviceName == null) { + if (mMaster.verbose) { + Slog.v(TAG, "ensureRemoteServiceLocked(): no service component name."); + } + return null; + } + final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); + mRemoteTranslationService = new RemoteTranslationService(getContext(), + serviceComponent, mUserId, /* isInstantAllowed= */ false); + } + return mRemoteTranslationService; + } + + @GuardedBy("mLock") + void getSupportedLocalesLocked(@NonNull IResultReceiver resultReceiver) { + // TODO: implement this + try { + resultReceiver.send(STATUS_SYNC_CALL_SUCCESS, + SyncResultReceiver.bundleFor(new ArrayList<>())); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException returning supported locales: " + e); + } + } + + @GuardedBy("mLock") + void onSessionCreatedLocked(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, int sessionId, IResultReceiver resultReceiver) { + final RemoteTranslationService remoteService = ensureRemoteServiceLocked(); + if (remoteService != null) { + remoteService.onSessionCreated(sourceSpec, destSpec, sessionId, resultReceiver); + } + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 3433880f3c0e..e318207cdc75 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -1199,6 +1199,8 @@ public class ConnectivityServiceTest { updateState(NetworkInfo.DetailedState.DISCONNECTED, "disconnect"); } mAgentRegistered = false; + setUids(null); + mInterface = null; } @Override @@ -3624,51 +3626,55 @@ public class ConnectivityServiceTest { // Register the factory and expect it to start looking for a network. testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet. testFactory.register(); - testFactory.waitForNetworkRequests(1); - assertTrue(testFactory.getMyStartRequested()); - // Bring up wifi. The factory stops looking for a network. - mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); - // Score 60 - 40 penalty for not validated yet, then 60 when it validates - testFactory.expectAddRequestsWithScores(20, 60); - mWiFiNetworkAgent.connect(true); - testFactory.waitForRequests(); - assertFalse(testFactory.getMyStartRequested()); - - ContentResolver cr = mServiceContext.getContentResolver(); - - // Turn on mobile data always on. The factory starts looking again. - testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0 - setAlwaysOnNetworks(true); - testFactory.waitForNetworkRequests(2); - assertTrue(testFactory.getMyStartRequested()); - - // Bring up cell data and check that the factory stops looking. - assertLength(1, mCm.getAllNetworks()); - mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); - testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated - mCellNetworkAgent.connect(true); - cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); - testFactory.waitForNetworkRequests(2); - assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us. + try { + testFactory.waitForNetworkRequests(1); + assertTrue(testFactory.getMyStartRequested()); - // Check that cell data stays up. - waitForIdle(); - verifyActiveNetwork(TRANSPORT_WIFI); - assertLength(2, mCm.getAllNetworks()); + // Bring up wifi. The factory stops looking for a network. + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + // Score 60 - 40 penalty for not validated yet, then 60 when it validates + testFactory.expectAddRequestsWithScores(20, 60); + mWiFiNetworkAgent.connect(true); + testFactory.waitForRequests(); + assertFalse(testFactory.getMyStartRequested()); - // Turn off mobile data always on and expect the request to disappear... - testFactory.expectRemoveRequests(1); - setAlwaysOnNetworks(false); - testFactory.waitForNetworkRequests(1); + ContentResolver cr = mServiceContext.getContentResolver(); + + // Turn on mobile data always on. The factory starts looking again. + testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0 + setAlwaysOnNetworks(true); + testFactory.waitForNetworkRequests(2); + assertTrue(testFactory.getMyStartRequested()); + + // Bring up cell data and check that the factory stops looking. + assertLength(1, mCm.getAllNetworks()); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated + mCellNetworkAgent.connect(true); + cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + testFactory.waitForNetworkRequests(2); + assertFalse( + testFactory.getMyStartRequested()); // Because the cell network outscores us. + + // Check that cell data stays up. + waitForIdle(); + verifyActiveNetwork(TRANSPORT_WIFI); + assertLength(2, mCm.getAllNetworks()); - // ... and cell data to be torn down. - cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); - assertLength(1, mCm.getAllNetworks()); + // Turn off mobile data always on and expect the request to disappear... + testFactory.expectRemoveRequests(1); + setAlwaysOnNetworks(false); + testFactory.waitForNetworkRequests(1); - testFactory.terminate(); - mCm.unregisterNetworkCallback(cellNetworkCallback); - handlerThread.quit(); + // ... and cell data to be torn down. + cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + assertLength(1, mCm.getAllNetworks()); + } finally { + testFactory.terminate(); + mCm.unregisterNetworkCallback(cellNetworkCallback); + handlerThread.quit(); + } } @Test @@ -6176,11 +6182,15 @@ public class ConnectivityServiceTest { // Create a fake restricted profile whose parent is our user ID. final int userId = UserHandle.getUserId(uid); + when(mUserManager.canHaveRestrictedProfile(userId)).thenReturn(true); final int restrictedUserId = userId + 1; final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED); info.restrictedProfileParentId = userId; assertTrue(info.isRestricted()); when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info); + when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId)) + .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID)); + final Intent addedIntent = new Intent(ACTION_USER_ADDED); addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); @@ -6220,6 +6230,54 @@ public class ConnectivityServiceTest { && caps.getUids().contains(new UidRange(uid, uid)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); + + // Test lockdown with restricted profiles. + mServiceContext.setPermission( + Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED); + mServiceContext.setPermission( + Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED); + mServiceContext.setPermission( + Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + + // Connect wifi and check that UIDs in the main and restricted profiles have network access. + mMockVpn.disconnect(); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true /* validated */); + final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */); + assertNotNull(mCm.getActiveNetworkForUid(uid)); + assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); + + // Enable always-on VPN lockdown. The main user loses network access because no VPN is up. + final ArrayList<String> allowList = new ArrayList<>(); + mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + waitForIdle(); + assertNull(mCm.getActiveNetworkForUid(uid)); + assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); + + // Start the restricted profile, and check that the UID within it loses network access. + when(mUserManager.getAliveUsers()).thenReturn( + Arrays.asList(new UserInfo[] { + new UserInfo(userId, "", 0), + info + })); + // TODO: check that VPN app within restricted profile still has access, etc. + handler.post(() -> mServiceContext.sendBroadcast(addedIntent)); + waitForIdle(); + assertNull(mCm.getActiveNetworkForUid(uid)); + assertNull(mCm.getActiveNetworkForUid(restrictedUid)); + + // Stop the restricted profile, and check that the UID within it has network access again. + when(mUserManager.getAliveUsers()).thenReturn( + Arrays.asList(new UserInfo[] { + new UserInfo(userId, "", 0), + })); + handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); + waitForIdle(); + assertNull(mCm.getActiveNetworkForUid(uid)); + assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); + + mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); + waitForIdle(); } @Test diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 3648c4db1e16..02a2aadc4c79 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -339,14 +339,8 @@ public class VpnTest { final Vpn vpn = createVpn(primaryUser.id); final UidRange user = PRI_USER_RANGE; - // Default state. - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], - user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); - // Set always-on without lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore)); - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], - user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore)); @@ -355,10 +349,6 @@ public class VpnTest { new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], - user.start + PKG_UIDS[3]); - assertUnblocked(vpn, user.start + PKG_UIDS[1]); - // Switch to another app. assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { @@ -369,9 +359,6 @@ public class VpnTest { new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], - user.start + PKG_UIDS[2]); - assertUnblocked(vpn, user.start + PKG_UIDS[3]); } @Test @@ -386,8 +373,6 @@ public class VpnTest { new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); - assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); @@ -398,8 +383,6 @@ public class VpnTest { new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]); - assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]); // Change the VPN app. assertTrue(vpn.setAlwaysOnPackage( @@ -412,8 +395,6 @@ public class VpnTest { new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1), new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) })); - assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); // Remove the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); @@ -424,9 +405,6 @@ public class VpnTest { verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop), })); - assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], - user.start + PKG_UIDS[3]); - assertUnblocked(vpn, user.start + PKG_UIDS[0]); // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( @@ -438,8 +416,6 @@ public class VpnTest { new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); - assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); - assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); // Try allowing a package with a comma, should be rejected. assertFalse(vpn.setAlwaysOnPackage( @@ -460,45 +436,6 @@ public class VpnTest { } @Test - public void testLockdownAddingAProfile() throws Exception { - final Vpn vpn = createVpn(primaryUser.id); - setMockedUsers(primaryUser); - - // Make a copy of the restricted profile, as we're going to mark it deleted halfway through. - final UserInfo tempProfile = new UserInfo(restrictedProfileA.id, restrictedProfileA.name, - restrictedProfileA.flags); - tempProfile.restrictedProfileParentId = primaryUser.id; - - final UidRange user = PRI_USER_RANGE; - final UidRange profile = UidRange.createForUser(tempProfile.id); - - // Set lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); - verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), - new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) - })); - // Verify restricted user isn't affected at first. - assertUnblocked(vpn, profile.start + PKG_UIDS[0]); - - // Add the restricted user. - setMockedUsers(primaryUser, tempProfile); - vpn.onUserAdded(tempProfile.id); - verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1), - new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop) - })); - - // Remove the restricted user. - tempProfile.partial = true; - vpn.onUserRemoved(tempProfile.id); - verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { - new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1), - new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop) - })); - } - - @Test public void testLockdownRuleRepeatability() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] { @@ -1207,20 +1144,6 @@ public class VpnTest { return vpn; } - private static void assertBlocked(Vpn vpn, int... uids) { - for (int uid : uids) { - final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid); - assertTrue("Uid " + uid + " should be blocked", blocked); - } - } - - private static void assertUnblocked(Vpn vpn, int... uids) { - for (int uid : uids) { - final boolean blocked = vpn.getLockdown() && vpn.isBlockingUid(uid); - assertFalse("Uid " + uid + " should not be blocked", blocked); - } - } - /** * Populate {@link #mUserManager} with a list of fake users. */ |