diff options
273 files changed, 4282 insertions, 1791 deletions
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp index 9f795a7ed54a..c40e0252cb7e 100644 --- a/apct-tests/perftests/textclassifier/Android.bp +++ b/apct-tests/perftests/textclassifier/Android.bp @@ -19,7 +19,7 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", - "collector-device-lib-platform", + "collector-device-lib", ], data: [":perfetto_artifacts"], platform_apis: true, diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index 3f3b8eaffdab..f53ac8c895ce 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -39,6 +39,14 @@ package android.media { } +package android.media.session { + + public final class MediaSession { + field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000 + } + +} + package android.net { public final class TetheringConstants { diff --git a/api/system-current.txt b/api/system-current.txt index 56059dd9d864..88fe40a93010 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12732,6 +12732,9 @@ package android.webkit { public interface PacProcessor { method @Nullable public String findProxyForUrl(@NonNull String); method @NonNull public static android.webkit.PacProcessor getInstance(); + method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long); + method public default long getNetworkHandle(); + method public default void releasePacProcessor(); method public boolean setProxyScript(@NonNull String); } @@ -12871,6 +12874,7 @@ package android.webkit { method public android.webkit.CookieManager getCookieManager(); method public android.webkit.GeolocationPermissions getGeolocationPermissions(); method @NonNull public default android.webkit.PacProcessor getPacProcessor(); + method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long); method public android.webkit.ServiceWorkerController getServiceWorkerController(); method public android.webkit.WebViewFactoryProvider.Statics getStatics(); method @Deprecated public android.webkit.TokenBindingService getTokenBindingService(); diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index ed717c491467..4b7eda096e54 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -19,6 +19,7 @@ package com.android.commands.bmgr; import android.annotation.IntDef; import android.annotation.UserIdInt; import android.app.backup.BackupManager; +import android.app.backup.BackupManager.OperationType; import android.app.backup.BackupManagerMonitor; import android.app.backup.BackupProgress; import android.app.backup.BackupTransport; @@ -666,7 +667,7 @@ public class Bmgr { // The rest of the 'list' options work with a restore session on the current transport try { - mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null); + mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP); if (mRestore == null) { System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId); return; @@ -821,7 +822,7 @@ public class Bmgr { try { boolean didRestore = false; - mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null); + mRestore = mBmgr.beginRestoreSessionForUser(userId, null, null, OperationType.BACKUP); if (mRestore == null) { System.err.println(BMGR_ERR_NO_RESTORESESSION_FOR_USER + userId); return; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index ca22bf4a62dc..d334de60713a 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -364,6 +364,18 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000; + /** + * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled, + * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected, + * but instead passed through as one-finger gestures. In addition, three-finger swipes from the + * bottom of the screen are not detected, and instead are passed through unchanged. If {@link + * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect. + * + * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + * @hide + */ + public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000; + /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -624,6 +636,7 @@ public class AccessibilityServiceInfo implements Parcelable { 0); flags = asAttributes.getInt( com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); + flags |= FLAG_REQUEST_2_FINGER_PASSTHROUGH; mSettingsActivityName = asAttributes.getString( com.android.internal.R.styleable.AccessibilityService_settingsActivity); if (asAttributes.getBoolean(com.android.internal.R.styleable @@ -1261,6 +1274,8 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; case FLAG_REQUEST_MULTI_FINGER_GESTURES: return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; + case FLAG_REQUEST_2_FINGER_PASSTHROUGH: + return "FLAG_REQUEST_2_FINGER_PASSTHROUGH"; case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; case FLAG_REPORT_VIEW_IDS: diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9b13d256aea6..7cec717f96e0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -37,6 +37,7 @@ import android.annotation.Nullable; import android.app.assist.AssistContent; import android.app.assist.AssistStructure; import android.app.backup.BackupAgent; +import android.app.backup.BackupManager; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityLifecycleItem.LifecycleState; import android.app.servertransaction.ActivityRelaunchItem; @@ -289,6 +290,8 @@ public final class ActivityThread extends ClientTransactionHandler { private final Object mNetworkPolicyLock = new Object(); + private static final String DEFAULT_FULL_BACKUP_AGENT = "android.app.backup.FullBackupAgent"; + /** * Denotes the sequence number of the process state change for which the main thread needs * to block until the network rules are updated for it. @@ -737,6 +740,7 @@ public final class ActivityThread extends ClientTransactionHandler { CompatibilityInfo compatInfo; int backupMode; int userId; + int operationType; public String toString() { return "CreateBackupAgentData{appInfo=" + appInfo + " backupAgent=" + appInfo.backupAgentName @@ -957,12 +961,13 @@ public final class ActivityThread extends ClientTransactionHandler { } public final void scheduleCreateBackupAgent(ApplicationInfo app, - CompatibilityInfo compatInfo, int backupMode, int userId) { + CompatibilityInfo compatInfo, int backupMode, int userId, int operationType) { CreateBackupAgentData d = new CreateBackupAgentData(); d.appInfo = app; d.compatInfo = compatInfo; d.backupMode = backupMode; d.userId = userId; + d.operationType = operationType; sendMessage(H.CREATE_BACKUP_AGENT, d); } @@ -4075,12 +4080,7 @@ public final class ActivityThread extends ClientTransactionHandler { return; } - String classname = data.appInfo.backupAgentName; - // full backup operation but no app-supplied agent? use the default implementation - if (classname == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL - || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { - classname = "android.app.backup.FullBackupAgent"; - } + String classname = getBackupAgentName(data); try { IBinder binder = null; @@ -4104,7 +4104,7 @@ public final class ActivityThread extends ClientTransactionHandler { context.setOuterContext(agent); agent.attach(context); - agent.onCreate(UserHandle.of(data.userId)); + agent.onCreate(UserHandle.of(data.userId), data.operationType); binder = agent.onBind(); backupAgents.put(packageName, agent); } catch (Exception e) { @@ -4132,6 +4132,23 @@ public final class ActivityThread extends ClientTransactionHandler { } } + private String getBackupAgentName(CreateBackupAgentData data) { + String agentName = data.appInfo.backupAgentName; + if (!UserHandle.isCore(data.appInfo.uid) + && data.operationType == BackupManager.OperationType.MIGRATION) { + // If this is a migration, use the default backup agent regardless of the app's + // preferences. + agentName = DEFAULT_FULL_BACKUP_AGENT; + } else { + // full backup operation but no app-supplied agent? use the default implementation + if (agentName == null && (data.backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL + || data.backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL)) { + agentName = DEFAULT_FULL_BACKUP_AGENT; + } + } + return agentName; + } + // Tear down a BackupAgent private void handleDestroyBackupAgent(CreateBackupAgentData data) { if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data); @@ -5111,6 +5128,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } r.setState(ON_DESTROY); + mLastReportedWindowingMode.remove(r.activity.getActivityToken()); } schedulePurgeIdler(); // updatePendingActivityConfiguration() reads from mActivities to update @@ -5353,16 +5371,8 @@ public final class ActivityThread extends ClientTransactionHandler { throw e.rethrowFromSystemServer(); } - // Save the current windowing mode to be restored and compared to the new configuration's - // windowing mode (needed because we update the last reported windowing mode when launching - // an activity and we can't tell inside performLaunchActivity whether we are relaunching) - final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault( - r.activity.getActivityToken(), WINDOWING_MODE_UNDEFINED); handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents, pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity"); - mLastReportedWindowingMode.put(r.activity.getActivityToken(), oldWindowingMode); - handleWindowingModeChangeIfNeeded(r.activity, r.activity.mCurrentConfig); - if (pendingActions != null) { // Only report a successful relaunch to WindowManager. pendingActions.setReportRelaunchToWindowManager(true); @@ -5628,10 +5638,6 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalArgumentException("Activity token not set. Is the activity attached?"); } - // multi-window / pip mode changes, if any, should be sent before the configuration change - // callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition - handleWindowingModeChangeIfNeeded(activity, newConfig); - final boolean movedToDifferentDisplay = isDifferentDisplay(activity, displayId); boolean shouldReportChange = false; if (activity.mCurrentConfig == null) { @@ -5685,6 +5691,11 @@ public final class ActivityThread extends ClientTransactionHandler { } if (shouldReportChange) { + // multi-window / pip mode changes, if any, should be sent before the configuration + // change callback, see also + // PinnedStackTests#testConfigurationChangeOrderDuringTransition + handleWindowingModeChangeIfNeeded(activity, newConfig); + activity.mCalled = false; activity.onConfigurationChanged(configToReport); if (!activity.mCalled) { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 3b6a7b8f7592..99640118ccdf 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -288,7 +288,8 @@ interface IActivityManager { void stopAppSwitches(); @UnsupportedAppUsage void resumeAppSwitches(); - boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId); + boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId, + int operationType); void backupAgentCreated(in String packageName, in IBinder agent, int userId); void unbindBackupAgent(in ApplicationInfo appInfo); int getUidForIntentSender(in IIntentSender sender); diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 6e9157e2a8c3..24da50481df3 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -95,7 +95,7 @@ oneway interface IApplicationThread { void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType); void setSchedulingGroup(int group); void scheduleCreateBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, - int backupMode, int userId); + int backupMode, int userId, int operationType); void scheduleDestroyBackupAgent(in ApplicationInfo app, in CompatibilityInfo compatInfo, int userId); void scheduleOnNewActivityOptions(IBinder token, in Bundle options); diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index bca6f39e1ded..54f3f1026050 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -215,7 +215,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { private long mMisses = 0; @GuardedBy("mLock") - private long mMissDisabled[] = new long[]{ 0, 0, 0 }; + private long mSkips[] = new long[]{ 0, 0, 0 }; @GuardedBy("mLock") private long mMissOverflow = 0; @@ -223,6 +223,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> { @GuardedBy("mLock") private long mHighWaterMark = 0; + @GuardedBy("mLock") + private long mClears = 0; + // Most invalidation is done in a static context, so the counters need to be accessible. @GuardedBy("sCorkLock") private static final HashMap<String, Long> sInvalidates = new HashMap<>(); @@ -273,6 +276,13 @@ public abstract class PropertyInvalidatedCache<Query, Result> { */ private volatile SystemProperties.Handle mPropertyHandle; + /** + * The name by which this cache is known. This should normally be the + * binder call that is being cached, but the constructors default it to + * the property name. + */ + private final String mCacheName; + @GuardedBy("mLock") private final LinkedHashMap<Query, Result> mCache; @@ -297,9 +307,23 @@ public abstract class PropertyInvalidatedCache<Query, Result> { * * @param maxEntries Maximum number of entries to cache; LRU discard * @param propertyName Name of the system property holding the cache invalidation nonce + * Defaults the cache name to the property name. */ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) { + this(maxEntries, propertyName, propertyName); + } + + /** + * Make a new property invalidated cache. + * + * @param maxEntries Maximum number of entries to cache; LRU discard + * @param propertyName Name of the system property holding the cache invalidation nonce + * @param cacheName Name of this cache in debug and dumpsys + */ + public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName, + @NonNull String cacheName) { mPropertyName = propertyName; + mCacheName = cacheName; mMaxEntries = maxEntries; mCache = new LinkedHashMap<Query, Result>( 2 /* start small */, @@ -320,7 +344,6 @@ public abstract class PropertyInvalidatedCache<Query, Result> { }; synchronized (sCorkLock) { sCaches.put(this, null); - sInvalidates.put(propertyName, (long) 0); } } @@ -333,6 +356,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { Log.d(TAG, "clearing cache for " + mPropertyName); } mCache.clear(); + mClears++; } } @@ -413,7 +437,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { // Do not bother collecting statistics if the cache is // locally disabled. synchronized (mLock) { - mMissDisabled[(int) currentNonce]++; + mSkips[(int) currentNonce]++; } } @@ -742,12 +766,16 @@ public abstract class PropertyInvalidatedCache<Query, Result> { boolean alreadyQueued = mUncorkDeadlineMs >= 0; if (DEBUG) { Log.w(TAG, String.format( - "autoCork mUncorkDeadlineMs=%s", mUncorkDeadlineMs)); + "autoCork %s mUncorkDeadlineMs=%s", mPropertyName, + mUncorkDeadlineMs)); } mUncorkDeadlineMs = SystemClock.uptimeMillis() + mAutoCorkDelayMs; if (!alreadyQueued) { getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs); PropertyInvalidatedCache.corkInvalidations(mPropertyName); + } else { + final long count = sCorkedInvalidates.getOrDefault(mPropertyName, (long) 0); + sCorkedInvalidates.put(mPropertyName, count + 1); } } } @@ -756,7 +784,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { synchronized (mLock) { if (DEBUG) { Log.w(TAG, String.format( - "handleMsesage mUncorkDeadlineMs=%s", mUncorkDeadlineMs)); + "handleMsesage %s mUncorkDeadlineMs=%s", + mPropertyName, mUncorkDeadlineMs)); } if (mUncorkDeadlineMs < 0) { @@ -816,7 +845,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { * method is public so clients can use it. */ public String cacheName() { - return mPropertyName; + return mCacheName; } /** @@ -864,16 +893,20 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } synchronized (mLock) { - pw.println(String.format(" Cache Property Name: %s", cacheName())); - pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d, Overflows: %d", - mHits, mMisses, invalidateCount, mMissOverflow)); - pw.println(String.format(" Miss-corked: %d, Miss-unset: %d, Miss-other: %d," + - " CorkedInvalidates: %d", - mMissDisabled[NONCE_CORKED], mMissDisabled[NONCE_UNSET], - mMissDisabled[NONCE_DISABLED], corkedInvalidates)); - pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce)); - pw.println(String.format(" Current Size: %d, Max Size: %d, HW Mark: %d", - mCache.size(), mMaxEntries, mHighWaterMark)); + pw.println(String.format(" Cache Name: %s", cacheName())); + pw.println(String.format(" Property: %s", mPropertyName)); + final long skips = mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED]; + pw.println(String.format(" Hits: %d, Misses: %d, Skips: %d, Clears: %d", + mHits, mMisses, skips, mClears)); + pw.println(String.format(" Skip-corked: %d, Skip-unset: %d, Skip-other: %d", + mSkips[NONCE_CORKED], mSkips[NONCE_UNSET], + mSkips[NONCE_DISABLED])); + pw.println(String.format( + " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d", + mLastSeenNonce, invalidateCount, corkedInvalidates)); + pw.println(String.format( + " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d", + mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow)); pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true")); Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet(); diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 7c6eff143724..06d1b74abc86 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -510,6 +510,9 @@ public class UiModeManager { } /** + * Activating night mode for the current user + * + * @return {@code true} if the change is successful * @hide */ public boolean setNightModeActivated(boolean active) { diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index a789169ade39..16ddcd1d0ea3 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -19,6 +19,7 @@ package android.app.backup; import android.annotation.Nullable; import android.app.IBackupAgent; import android.app.QueuedWork; +import android.app.backup.BackupManager.OperationType; import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; import android.content.Context; import android.content.ContextWrapper; @@ -38,6 +39,8 @@ import android.system.StructStat; import android.util.ArraySet; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParserException; @@ -50,6 +53,7 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -129,6 +133,7 @@ import java.util.concurrent.CountDownLatch; public abstract class BackupAgent extends ContextWrapper { private static final String TAG = "BackupAgent"; private static final boolean DEBUG = false; + private static final int DEFAULT_OPERATION_TYPE = OperationType.BACKUP; /** @hide */ public static final int RESULT_SUCCESS = 0; @@ -186,6 +191,9 @@ public abstract class BackupAgent extends ContextWrapper { Handler mHandler = null; @Nullable private UserHandle mUser; + // This field is written from the main thread (in onCreate), and read in a Binder thread (in + // onFullBackup that is called from system_server via Binder). + @OperationType private volatile int mOperationType = DEFAULT_OPERATION_TYPE; Handler getHandler() { if (mHandler == null) { @@ -229,6 +237,13 @@ public abstract class BackupAgent extends ContextWrapper { } /** + * @hide + */ + public void onCreate(UserHandle user) { + onCreate(user, DEFAULT_OPERATION_TYPE); + } + + /** * Provided as a convenience for agent implementations that need an opportunity * to do one-time initialization before the actual backup or restore operation * is begun with information about the calling user. @@ -236,10 +251,11 @@ public abstract class BackupAgent extends ContextWrapper { * * @hide */ - public void onCreate(UserHandle user) { + public void onCreate(UserHandle user, @OperationType int operationType) { onCreate(); mUser = user; + mOperationType = operationType; } /** @@ -390,12 +406,9 @@ public abstract class BackupAgent extends ContextWrapper { return; } - Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; - ArraySet<PathWithRequiredFlags> manifestExcludeSet; + IncludeExcludeRules includeExcludeRules; try { - manifestIncludeMap = - backupScheme.maybeParseAndGetCanonicalIncludePaths(); - manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); + includeExcludeRules = getIncludeExcludeRules(backupScheme); } catch (IOException | XmlPullParserException e) { if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) { Log.v(FullBackup.TAG_XML_PARSER, @@ -404,6 +417,10 @@ public abstract class BackupAgent extends ContextWrapper { } return; } + Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap + = includeExcludeRules.getIncludeMap(); + Set<PathWithRequiredFlags> manifestExcludeSet + = includeExcludeRules.getExcludeSet(); final String packageName = getPackageName(); final ApplicationInfo appInfo = getApplicationInfo(); @@ -528,6 +545,24 @@ public abstract class BackupAgent extends ContextWrapper { } } + /** @hide */ + @VisibleForTesting + public IncludeExcludeRules getIncludeExcludeRules(FullBackup.BackupScheme backupScheme) + throws IOException, XmlPullParserException { + if (mOperationType == OperationType.MIGRATION) { + return IncludeExcludeRules.emptyRules(); + } + + Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap; + ArraySet<PathWithRequiredFlags> manifestExcludeSet; + + manifestIncludeMap = + backupScheme.maybeParseAndGetCanonicalIncludePaths(); + manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths(); + + return new IncludeExcludeRules(manifestIncludeMap, manifestExcludeSet); + } + /** * Notification that the application's current backup operation causes it to exceed * the maximum size permitted by the transport. The ongoing backup operation is @@ -570,7 +605,7 @@ public abstract class BackupAgent extends ContextWrapper { */ private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken, Map<String, Set<PathWithRequiredFlags>> includeMap, - ArraySet<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, + Set<PathWithRequiredFlags> filterSet, ArraySet<String> traversalExcludeSet, FullBackupDataOutput data) throws IOException { if (includeMap == null || includeMap.size() == 0) { // Do entire sub-tree for the provided token. @@ -742,7 +777,7 @@ public abstract class BackupAgent extends ContextWrapper { * @hide */ protected final void fullBackupFileTree(String packageName, String domain, String startingPath, - ArraySet<PathWithRequiredFlags> manifestExcludes, + Set<PathWithRequiredFlags> manifestExcludes, ArraySet<String> systemExcludes, FullBackupDataOutput output) { // Pull out the domain and set it aside to use when making the tarball. @@ -811,7 +846,7 @@ public abstract class BackupAgent extends ContextWrapper { } private boolean manifestExcludesContainFilePath( - ArraySet<PathWithRequiredFlags> manifestExcludes, String filePath) { + Set<PathWithRequiredFlags> manifestExcludes, String filePath) { for (PathWithRequiredFlags exclude : manifestExcludes) { String excludePath = exclude.getPath(); if (excludePath != null && excludePath.equals(filePath)) { @@ -1265,4 +1300,53 @@ public abstract class BackupAgent extends ContextWrapper { throw new IllegalStateException(mMessage); } } + + /** @hide */ + @VisibleForTesting + public static class IncludeExcludeRules { + private final Map<String, Set<PathWithRequiredFlags>> mManifestIncludeMap; + private final Set<PathWithRequiredFlags> mManifestExcludeSet; + + /** @hide */ + public IncludeExcludeRules( + Map<String, Set<PathWithRequiredFlags>> manifestIncludeMap, + Set<PathWithRequiredFlags> manifestExcludeSet) { + mManifestIncludeMap = manifestIncludeMap; + mManifestExcludeSet = manifestExcludeSet; + } + + /** @hide */ + @VisibleForTesting + public static IncludeExcludeRules emptyRules() { + return new IncludeExcludeRules(Collections.emptyMap(), new ArraySet<>()); + } + + private Map<String, Set<PathWithRequiredFlags>> getIncludeMap() { + return mManifestIncludeMap; + } + + private Set<PathWithRequiredFlags> getExcludeSet() { + return mManifestExcludeSet; + } + + /** @hide */ + @Override + public int hashCode() { + return Objects.hash(mManifestIncludeMap, mManifestExcludeSet); + } + + /** @hide */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + IncludeExcludeRules that = (IncludeExcludeRules) object; + return Objects.equals(mManifestIncludeMap, that.mManifestIncludeMap) && + Objects.equals(mManifestExcludeSet, that.mManifestExcludeSet); + } + } } diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index b1a62bf42cc4..9b67587c4dcd 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -355,7 +355,36 @@ public class BackupManager { try { // All packages, current transport IRestoreSession binder = - sService.beginRestoreSessionForUser(mContext.getUserId(), null, null); + sService.beginRestoreSessionForUser(mContext.getUserId(), null, null, + OperationType.BACKUP); + if (binder != null) { + session = new RestoreSession(mContext, binder); + } + } catch (RemoteException e) { + Log.e(TAG, "beginRestoreSession() couldn't connect"); + } + } + return session; + } + + /** + * Begin the process of restoring data from backup. See the + * {@link android.app.backup.RestoreSession} class for documentation on that process. + * + * @param operationType Type of the operation, see {@link OperationType} + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.BACKUP) + public RestoreSession beginRestoreSession(@OperationType int operationType) { + RestoreSession session = null; + checkServiceBinder(); + if (sService != null) { + try { + // All packages, current transport + IRestoreSession binder = + sService.beginRestoreSessionForUser(mContext.getUserId(), null, null, + operationType); if (binder != null) { session = new RestoreSession(mContext, binder); } diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index 96b5dd593bbe..e177a74915ee 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -547,9 +547,11 @@ interface IBackupManager { * set can be restored. * @param transportID The name of the transport to use for the restore operation. * May be null, in which case the current active transport is used. + * @param operationType Type of the operation, see {@link BackupManager#OperationType} * @return An interface to the restore session, or null on error. */ - IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID); + IRestoreSession beginRestoreSessionForUser(int userId, String packageName, String transportID, + int operationType); /** * Notify the backup manager that a BackupAgent has completed the operation diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java new file mode 100644 index 000000000000..39c5c85e456c --- /dev/null +++ b/core/java/android/app/people/ConversationChannel.java @@ -0,0 +1,97 @@ +/* + * 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.app.people; + +import android.app.NotificationChannel; +import android.content.pm.ShortcutInfo; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The non-customized notification channel of a conversation. It contains the information to render + * the conversation and allows the user to open and customize the conversation setting. + * + * @hide + */ +public final class ConversationChannel implements Parcelable { + + private ShortcutInfo mShortcutInfo; + private NotificationChannel mParentNotificationChannel; + private long mLastEventTimestamp; + private boolean mHasActiveNotifications; + + public static final Creator<ConversationChannel> CREATOR = new Creator<ConversationChannel>() { + @Override + public ConversationChannel createFromParcel(Parcel in) { + return new ConversationChannel(in); + } + + @Override + public ConversationChannel[] newArray(int size) { + return new ConversationChannel[size]; + } + }; + + public ConversationChannel(ShortcutInfo shortcutInfo, + NotificationChannel parentNotificationChannel, long lastEventTimestamp, + boolean hasActiveNotifications) { + mShortcutInfo = shortcutInfo; + mParentNotificationChannel = parentNotificationChannel; + mLastEventTimestamp = lastEventTimestamp; + mHasActiveNotifications = hasActiveNotifications; + } + + public ConversationChannel(Parcel in) { + mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader()); + mParentNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader()); + mLastEventTimestamp = in.readLong(); + mHasActiveNotifications = in.readBoolean(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mShortcutInfo, flags); + dest.writeParcelable(mParentNotificationChannel, flags); + dest.writeLong(mLastEventTimestamp); + dest.writeBoolean(mHasActiveNotifications); + } + + public ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + + public NotificationChannel getParentNotificationChannel() { + return mParentNotificationChannel; + } + + public long getLastEventTimestamp() { + return mLastEventTimestamp; + } + + /** + * Whether this conversation has any active notifications. If it's true, the shortcut for this + * conversation can't be uncached until all its active notifications are dismissed. + */ + public boolean hasActiveNotifications() { + return mHasActiveNotifications; + } +} diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl new file mode 100644 index 000000000000..61dac0d64422 --- /dev/null +++ b/core/java/android/app/people/IPeopleManager.aidl @@ -0,0 +1,42 @@ +/* + * 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.app.people; + +import android.content.pm.ParceledListSlice; +import android.net.Uri; +import android.os.IBinder; + +/** + * System private API for talking with the people service. + * {@hide} + */ +interface IPeopleManager { + /** + * Returns the recent conversations. The conversations that have customized notification + * settings are excluded from the returned list. + */ + ParceledListSlice getRecentConversations(); + + /** + * Removes the specified conversation from the recent conversations list and uncaches the + * shortcut associated with the conversation. + */ + void removeRecentConversation(in String packageName, int userId, in String shortcutId); + + /** Removes all the recent conversations and uncaches their cached shortcuts. */ + void removeAllRecentConversations(); +} diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java index 6bd365fad6f6..0770aff4e9bb 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java @@ -117,7 +117,7 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { } private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) { - ArraySet<TimeZoneConfigurationListener> configurationListeners; + final ArraySet<TimeZoneConfigurationListener> configurationListeners; synchronized (this) { configurationListeners = new ArraySet<>(mConfigurationListeners); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 16cdf2334ad8..52b04675b7a5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3496,6 +3496,7 @@ public abstract class Context { //@hide: TIME_ZONE_DETECTOR_SERVICE, PERMISSION_SERVICE, LIGHTS_SERVICE, + //@hide: PEOPLE_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ServiceName {} @@ -5189,6 +5190,14 @@ public abstract class Context { public static final String SMS_SERVICE = "sms"; /** + * Use with {@link #getSystemService(String)} to access people service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String PEOPLE_SERVICE = "people"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 42a610700051..e08af5534afd 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8089,7 +8089,8 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo> sApplicationInfoCache = new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>( - 16, PermissionManager.CACHE_KEY_PACKAGE_INFO) { + 16, PermissionManager.CACHE_KEY_PACKAGE_INFO, + "getApplicationInfo") { @Override protected ApplicationInfo recompute(ApplicationInfoQuery query) { return getApplicationInfoAsUserUncached( @@ -8190,7 +8191,8 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo> sPackageInfoCache = new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>( - 32, PermissionManager.CACHE_KEY_PACKAGE_INFO) { + 32, PermissionManager.CACHE_KEY_PACKAGE_INFO, + "getPackageInfo") { @Override protected PackageInfo recompute(PackageInfoQuery query) { return getPackageInfoAsUserUncached( diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java index f69bbe508492..f0a83f0b00b0 100644 --- a/core/java/android/hardware/camera2/CameraCaptureSession.java +++ b/core/java/android/hardware/camera2/CameraCaptureSession.java @@ -999,7 +999,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * <p>If the camera device configuration fails, then {@link #onConfigureFailed} will * be invoked instead of this callback.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the successfully configured session instance */ public abstract void onConfigured(@NonNull CameraCaptureSession session); @@ -1014,7 +1014,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * to the session prior to this callback will be discarded and will not produce any * callbacks on their listeners.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the session instance that failed during configuration */ public abstract void onConfigureFailed(@NonNull CameraCaptureSession session); @@ -1028,7 +1028,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * <p>Otherwise, this callback will be invoked any time the session finishes processing * all of its active capture requests, and no repeating request or burst is set up.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the session returned by {@link #onConfigured} * */ public void onReady(@NonNull CameraCaptureSession session) { @@ -1045,7 +1045,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * <p>If the session runs out of capture requests to process and calls {@link #onReady}, * then this callback will be invoked again once new requests are submitted for capture.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the session returned by {@link #onConfigured} */ public void onActive(@NonNull CameraCaptureSession session) { // default empty implementation @@ -1075,7 +1075,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * {@link #onReady}, which is fired when all requests in both queues have been processed.</p> * * @param session - * The session returned by {@link CameraDevice#createCaptureSession} + * The session returned by {@link #onConfigured} */ public void onCaptureQueueEmpty(@NonNull CameraCaptureSession session) { // default empty implementation @@ -1093,7 +1093,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * However, any in-progress capture requests submitted to the session will be completed * as normal.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the session returned by {@link #onConfigured} */ public void onClosed(@NonNull CameraCaptureSession session) { // default empty implementation @@ -1111,7 +1111,7 @@ public abstract class CameraCaptureSession implements AutoCloseable { * this callback is still invoked after the error is encountered, though some buffers may * not have been successfully pre-allocated.</p> * - * @param session the session returned by {@link CameraDevice#createCaptureSession} + * @param session the session returned by {@link #onConfigured} * @param surface the Surface that was used with the {@link #prepare} call. */ public void onSurfacePrepared(@NonNull CameraCaptureSession session, diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index 7ac8d052ea86..c7f89151624d 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -260,6 +260,13 @@ public abstract class DisplayManagerInternal { int displayId, long maxFrames, long timestamp); /** + * Temporarily ignore proximity-sensor-based display behavior until there is a change + * to the proximity sensor state. This allows the display to turn back on even if something + * is obstructing the proximity sensor. + */ + public abstract void ignoreProximitySensorUntilChanged(); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index ba0636fa80ff..dc6f5799156d 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -23,6 +23,7 @@ import android.hardware.input.IInputDevicesChangedListener; import android.hardware.input.ITabletModeChangedListener; import android.hardware.input.TouchCalibration; import android.os.IBinder; +import android.os.VibrationEffect; import android.view.InputDevice; import android.view.InputEvent; import android.view.InputMonitor; @@ -83,7 +84,7 @@ interface IInputManager { int isMicMuted(); // Input device vibrator control. - void vibrate(int deviceId, in long[] pattern, in int[] amplitudes, int repeat, IBinder token); + void vibrate(int deviceId, in VibrationEffect effect, IBinder token); void cancelVibrate(int deviceId, IBinder token); void setPointerIconType(int typeId); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index f0faeb078386..dd820fae3f2d 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1297,27 +1297,8 @@ public final class InputManager { @Override public void vibrate(int uid, String opPkg, VibrationEffect effect, String reason, AudioAttributes attributes) { - long[] pattern; - int[] amplitudes; - int repeat; - if (effect instanceof VibrationEffect.OneShot) { - VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect; - pattern = new long[] { 0, oneShot.getDuration() }; - amplitudes = new int[] { 0, oneShot.getAmplitude() }; - repeat = -1; - } else if (effect instanceof VibrationEffect.Waveform) { - VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; - pattern = waveform.getTimings(); - amplitudes = waveform.getAmplitudes(); - repeat = waveform.getRepeatIndex(); - } else { - // TODO: Add support for prebaked effects - Log.w(TAG, "Pre-baked effects aren't supported on input devices"); - return; - } - try { - mIm.vibrate(mDeviceId, pattern, amplitudes, repeat, mToken); + mIm.vibrate(mDeviceId, effect, mToken); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java index e30a40964992..eb18b96e255b 100644 --- a/core/java/android/os/PowerManagerInternal.java +++ b/core/java/android/os/PowerManagerInternal.java @@ -17,6 +17,7 @@ package android.os; import android.view.Display; +import android.view.KeyEvent; import java.util.function.Consumer; @@ -313,4 +314,7 @@ public abstract class PowerManagerInternal { /** Returns information about the last wakeup event. */ public abstract PowerManager.WakeData getLastWakeup(); + + /** Allows power button to intercept a power key button press. */ + public abstract boolean interceptPowerKeyDown(KeyEvent event); } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index bf3d46fa4a44..0c190719af57 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -608,7 +608,7 @@ public final class PermissionManager { /** @hide */ private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache = new PropertyInvalidatedCache<PermissionQuery, Integer>( - 16, CACHE_KEY_PACKAGE_INFO) { + 16, CACHE_KEY_PACKAGE_INFO, "checkPermission") { @Override protected Integer recompute(PermissionQuery query) { return checkPermissionUncached(query.permission, query.pid, query.uid); @@ -689,7 +689,7 @@ public final class PermissionManager { private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer> sPackageNamePermissionCache = new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>( - 16, CACHE_KEY_PACKAGE_INFO) { + 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") { @Override protected Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index c383bc7a4d70..7f45c044408a 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -618,16 +618,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return false; } if (DEBUG) Log.d(TAG, "onStateChanged: " + state); - updateState(state); - - boolean localStateChanged = !mState.equals(mLastDispatchedState, - true /* excludingCaptionInsets */, true /* excludeInvisibleIme */); mLastDispatchedState.set(state, true /* copySources */); + final InsetsState lastState = new InsetsState(mState, true /* copySources */); + updateState(state); applyLocalVisibilityOverride(); - if (localStateChanged) { - if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged, send state to WM: " + mState); + + if (!mState.equals(lastState, true /* excludingCaptionInsets */, + true /* excludeInvisibleIme */)) { + if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged"); mHost.notifyInsetsChanged(); + } + if (!mState.equals(state, true /* excludingCaptionInsets */, + true /* excludeInvisibleIme */)) { + if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState); updateRequestedState(); } return true; diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 50ed00cd0aa7..2ce993dfedca 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -2390,6 +2390,13 @@ public final class SurfaceControl implements Parcelable { } /** + * @hide + */ + public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) { + return nativeCaptureLayers(captureArgs); + } + + /** * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer * handles to exclude. * @hide diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl index eb67191e5f54..e814ec649087 100644 --- a/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl +++ b/core/java/android/view/accessibility/IWindowMagnificationConnection.aidl @@ -29,7 +29,7 @@ import android.view.accessibility.IWindowMagnificationConnectionCallback; oneway interface IWindowMagnificationConnection { /** - * Enables window magnification on specified display with given center and scale and animation. + * Enables window magnification on specifed display with specified center and scale. * * @param displayId The logical display id. * @param scale magnification scale. @@ -41,7 +41,7 @@ oneway interface IWindowMagnificationConnection { void enableWindowMagnification(int displayId, float scale, float centerX, float centerY); /** - * Sets the scale of the window magnifier on specified display. + * Sets the scale of the window magnifier on specifed display. * * @param displayId The logical display id. * @param scale magnification scale. @@ -49,14 +49,14 @@ oneway interface IWindowMagnificationConnection { void setScale(int displayId, float scale); /** - * Disables window magnification on specified display with animation. + * Disables window magnification on specifed display. * * @param displayId The logical display id. */ void disableWindowMagnification(int displayId); /** - * Moves the window magnifier on the specified display. It has no effect while animating. + * Moves the window magnifier on the specifed display. * * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in * current screen pixels. diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java index 5ef450fa65dd..7e7b987f72f3 100644 --- a/core/java/android/webkit/PacProcessor.java +++ b/core/java/android/webkit/PacProcessor.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; - +import android.net.Network; /** * Class to evaluate PAC scripts. @@ -40,6 +40,20 @@ public interface PacProcessor { } /** + * Returns PacProcessor instance associated with the {@link Network}. + * The host resolution is done on this {@link Network}. + * + * @param networkHandle a handle representing {@link Network} handle. + * @return PacProcessor instance for the specified network. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + @NonNull + static PacProcessor getInstanceForNetwork(long networkHandle) { + return WebViewFactory.getProvider().getPacProcessorForNetwork(networkHandle); + } + + /** * Set PAC script to use. * * @param script PAC script. @@ -55,4 +69,23 @@ public interface PacProcessor { */ @Nullable String findProxyForUrl(@NonNull String url); + + /** + * Stops support for this {@link PacProcessor} and release its resources. + * No methods of this class must be called after calling this method. + */ + default void releasePacProcessor() { + throw new UnsupportedOperationException("Not implemented"); + } + + /** + * Returns a network handle associated with this {@link PacProcessor}. + * + * @return a network handle or 0 if a network is unspecified. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + default long getNetworkHandle() { + throw new UnsupportedOperationException("Not implemented"); + } } diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index f7c3ec09dd67..f1863e319689 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; +import android.net.Network; import android.net.Uri; import java.util.List; @@ -175,7 +176,7 @@ public interface WebViewFactoryProvider { WebViewDatabase getWebViewDatabase(Context context); /** - * Gets the singleton PacProcessor instance. + * Gets the default PacProcessor instance. * @return the PacProcessor instance */ @NonNull @@ -184,6 +185,20 @@ public interface WebViewFactoryProvider { } /** + * Returns PacProcessor instance associated with the {@link Network}. + * The host resolution is done on this {@link Network}. + * + * @param networkHandle a network handle representing the {@link Network}. + * @return the {@link PacProcessor} instance associated with {@link Network}. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + @NonNull + default PacProcessor getPacProcessorForNetwork(long networkHandle) { + throw new UnsupportedOperationException("Not implemented"); + } + + /** * Gets the classloader used to load internal WebView implementation classes. This interface * should only be used by the WebView Support Library. */ diff --git a/core/java/com/android/internal/BrightnessSynchronizer.java b/core/java/com/android/internal/BrightnessSynchronizer.java index 42724bede481..f08d0ef8c052 100644 --- a/core/java/com/android/internal/BrightnessSynchronizer.java +++ b/core/java/com/android/internal/BrightnessSynchronizer.java @@ -83,63 +83,25 @@ public class BrightnessSynchronizer{ /** * Converts between the int brightness system and the float brightness system. */ - public static float brightnessIntToFloat(Context context, int brightnessInt) { - final PowerManager pm = context.getSystemService(PowerManager.class); - final float pmMinBrightness = pm.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM); - final float pmMaxBrightness = pm.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM); - final int minBrightnessInt = Math.round(brightnessFloatToIntRange(pmMinBrightness, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON)); - final int maxBrightnessInt = Math.round(brightnessFloatToIntRange(pmMaxBrightness, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON)); - - return brightnessIntToFloat(brightnessInt, minBrightnessInt, maxBrightnessInt, - pmMinBrightness, pmMaxBrightness); - } - - /** - * Converts between the int brightness system and the float brightness system. - */ - public static float brightnessIntToFloat(int brightnessInt, int minInt, int maxInt, - float minFloat, float maxFloat) { + public static float brightnessIntToFloat(int brightnessInt) { if (brightnessInt == PowerManager.BRIGHTNESS_OFF) { return PowerManager.BRIGHTNESS_OFF_FLOAT; } else if (brightnessInt == PowerManager.BRIGHTNESS_INVALID) { return PowerManager.BRIGHTNESS_INVALID_FLOAT; } else { - return MathUtils.constrainedMap(minFloat, maxFloat, (float) minInt, (float) maxInt, - brightnessInt); + final float minFloat = PowerManager.BRIGHTNESS_MIN; + final float maxFloat = PowerManager.BRIGHTNESS_MAX; + final float minInt = PowerManager.BRIGHTNESS_OFF + 1; + final float maxInt = PowerManager.BRIGHTNESS_ON; + return MathUtils.constrainedMap(minFloat, maxFloat, minInt, maxInt, brightnessInt); } } /** * Converts between the float brightness system and the int brightness system. */ - public static int brightnessFloatToInt(Context context, float brightnessFloat) { - return Math.round(brightnessFloatToIntRange(context, brightnessFloat)); - } - - /** - * Converts between the float brightness system and the int brightness system, but returns - * the converted value as a float within the int-system's range. This method helps with - * conversions from one system to the other without losing the floating-point precision. - */ - public static float brightnessFloatToIntRange(Context context, float brightnessFloat) { - final PowerManager pm = context.getSystemService(PowerManager.class); - final float minFloat = pm.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM); - final float maxFloat = pm.getBrightnessConstraint( - PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM); - final float minInt = brightnessFloatToIntRange(minFloat, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON); - final float maxInt = brightnessFloatToIntRange(maxFloat, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON); - return brightnessFloatToIntRange(brightnessFloat, minFloat, maxFloat, minInt, maxInt); + public static int brightnessFloatToInt(float brightnessFloat) { + return Math.round(brightnessFloatToIntRange(brightnessFloat)); } /** @@ -148,20 +110,24 @@ public class BrightnessSynchronizer{ * Value returned as a float privimite (to preserve precision), but is a value within the * int-system range. */ - private static float brightnessFloatToIntRange(float brightnessFloat, float minFloat, - float maxFloat, float minInt, float maxInt) { + public static float brightnessFloatToIntRange(float brightnessFloat) { if (floatEquals(brightnessFloat, PowerManager.BRIGHTNESS_OFF_FLOAT)) { return PowerManager.BRIGHTNESS_OFF; } else if (Float.isNaN(brightnessFloat)) { return PowerManager.BRIGHTNESS_INVALID; } else { + final float minFloat = PowerManager.BRIGHTNESS_MIN; + final float maxFloat = PowerManager.BRIGHTNESS_MAX; + final float minInt = PowerManager.BRIGHTNESS_OFF + 1; + final float maxInt = PowerManager.BRIGHTNESS_ON; return MathUtils.constrainedMap(minInt, maxInt, minFloat, maxFloat, brightnessFloat); } } private static float getScreenBrightnessFloat(Context context) { return Settings.System.getFloatForUser(context.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_FLOAT, Float.NaN, UserHandle.USER_CURRENT); + Settings.System.SCREEN_BRIGHTNESS_FLOAT, PowerManager.BRIGHTNESS_INVALID_FLOAT, + UserHandle.USER_CURRENT); } private static int getScreenBrightnessInt(Context context) { @@ -185,10 +151,10 @@ public class BrightnessSynchronizer{ if (topOfQueue != null && topOfQueue.equals(value)) { mWriteHistory.poll(); } else { - if (brightnessFloatToInt(mContext, mPreferredSettingValue) == value) { + if (brightnessFloatToInt(mPreferredSettingValue) == value) { return; } - float newBrightnessFloat = brightnessIntToFloat(mContext, value); + float newBrightnessFloat = brightnessIntToFloat(value); mWriteHistory.offer(newBrightnessFloat); mPreferredSettingValue = newBrightnessFloat; Settings.System.putFloatForUser(mContext.getContentResolver(), @@ -207,7 +173,7 @@ public class BrightnessSynchronizer{ * @param value Brightness setting as float to store in int setting. */ private void updateBrightnessIntFromFloat(float value) { - int newBrightnessInt = brightnessFloatToInt(mContext, value); + int newBrightnessInt = brightnessFloatToInt(value); Object topOfQueue = mWriteHistory.peek(); if (topOfQueue != null && topOfQueue.equals(value)) { mWriteHistory.poll(); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 49ad81b2bbc8..fe774780c133 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -784,8 +784,8 @@ public class ChooserActivity extends ResolverActivity implements FrameworkStatsLog.SHARESHEET_STARTED, getReferrerPackageName(), target.getType(), - initialIntents == null ? 0 : initialIntents.length, mCallerChooserTargets == null ? 0 : mCallerChooserTargets.length, + initialIntents == null ? 0 : initialIntents.length, isWorkProfile(), findPreferredContentPreview(getTargetIntent(), getContentResolver()), target.getAction() diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 5b22e3126eaf..1014fbb73877 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2698,4 +2698,9 @@ enum PageId { // CATEGORY: SETTINGS // OS: S EMERGENCY_SOS_GESTURE_SETTINGS = 1847; + + // OPEN: Settings > System > Gestures > Double tap + // CATEGORY: SETTINGS + // OS: S + SETTINGS_COLUMBUS = 1848; } diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index cff1218bd81b..56736c0d6780 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -976,7 +976,7 @@ <string name="save_password_remember" msgid="6490888932657708341">"Запомніць"</string> <string name="save_password_never" msgid="6776808375903410659">"Ніколі"</string> <string name="open_permission_deny" msgid="5136793905306987251">"У вас няма дазволу на адкрыццё гэтай старонкі."</string> - <string name="text_copied" msgid="2531420577879738860">"Тэкст скапіяваны ў буфер абмену."</string> + <string name="text_copied" msgid="2531420577879738860">"Тэкст скапіраваны ў буфер абмену."</string> <string name="copied" msgid="4675902854553014676">"Скапіравана"</string> <string name="more_item_label" msgid="7419249600215749115">"Больш"</string> <string name="prepend_shortcut_label" msgid="1743716737502867951">"Меню+"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 27ff3f0d4531..84f324356cd1 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1937,7 +1937,7 @@ <item quantity="one">Una sugerencia de Autocompletar</item> </plurals> <string name="autofill_save_title" msgid="7719802414283739775">"¿Quieres guardar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string> - <string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Quieres guardar <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string> + <string name="autofill_save_title_with_type" msgid="3002460014579799605">"¿Quieres guardar la <xliff:g id="TYPE">%1$s</xliff:g> en "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"¿Quieres guardar <xliff:g id="TYPE_0">%1$s</xliff:g> y <xliff:g id="TYPE_1">%2$s</xliff:g> en "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_3types" msgid="6598228952100102578">"¿Quieres guardar <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> y <xliff:g id="TYPE_2">%3$s</xliff:g> en "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"?"</string> <string name="autofill_update_title" msgid="3630695947047069136">"¿Quieres actualizar en "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index b115025fd63d..264a8fcb343d 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1894,7 +1894,7 @@ <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Այս հավելվածը ստեղծվել է Android-ի ավելի հին տարբերակի համար և կարող է պատշաճ չաշխատել: Ստուգեք թարմացումների առկայությունը կամ դիմեք մշակողին:"</string> <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Ստուգել նոր տարբերակի առկայությունը"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Դուք ունեք նոր հաղորդագրություններ"</string> - <string name="new_sms_notification_content" msgid="3197949934153460639">"Դիտելու համար բացել SMS հավելվածը"</string> + <string name="new_sms_notification_content" msgid="3197949934153460639">"Դիտելու համար բացել SMS-ների փոխանակման հավելվածը"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Որոշ գործառույթներ կարող են չաշխատել"</string> <string name="profile_encrypted_detail" msgid="5279730442756849055">"Աշխատանքային պրոֆիլը կողպված է"</string> <string name="profile_encrypted_message" msgid="1128512616293157802">"Հպեք՝ այն ապակողպելու համար"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 688996d87dba..085df65907f8 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -866,12 +866,12 @@ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan proses masuk Google.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Sudah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali Anda salah menggambar pola pembuka kunci. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci perangkat Android TV menggunakan login Google.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan proses masuk Google.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> upaya gagal lagi, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna hilang."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> upaya gagal lagi, tablet akan direset ke setelan default pabrik dan semua data pengguna hilang."</string> <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal membuka kunci perangkat Android TV. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, perangkat Android TV akan direset ke default pabrik dan semua data pengguna akan hilang."</string> - <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Anda telah gagal mencoba membuka gembok ponsel sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> upaya gagal lagi, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna hilang."</string> - <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Kini tablet akan disetel ulang ke setelan default pabrik."</string> + <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Anda telah gagal mencoba membuka gembok ponsel sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> upaya gagal lagi, ponsel akan direset ke setelan default pabrik dan semua data pengguna hilang."</string> + <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"Anda telah gagal mencoba membuka gembok tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Kini tablet akan direset ke setelan default pabrik."</string> <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal membuka kunci perangkat Android TV. Perangkat Android TV sekarang akan direset ke default pabrik."</string> - <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Anda telah gagal mencoba membuka gembok ponsel sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Kini ponsel akan disetel ulang ke setelan default pabrik."</string> + <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Anda telah gagal mencoba membuka gembok ponsel sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Kini ponsel akan direset ke setelan default pabrik."</string> <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"Coba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string> <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Lupa pola?"</string> <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Pembuka kunci akun"</string> @@ -1438,7 +1438,7 @@ <string name="vpn_lockdown_config" msgid="8331697329868252169">"Ubah setelan jaringan atau VPN"</string> <string name="upload_file" msgid="8651942222301634271">"Pilih file"</string> <string name="no_file_chosen" msgid="4146295695162318057">"Tidak ada file yang dipilih"</string> - <string name="reset" msgid="3865826612628171429">"Setel ulang"</string> + <string name="reset" msgid="3865826612628171429">"Reset"</string> <string name="submit" msgid="862795280643405865">"Kirim"</string> <string name="car_mode_disable_notification_title" msgid="8450693275833142896">"Aplikasi mengemudi sedang berjalan"</string> <string name="car_mode_disable_notification_message" msgid="8954550232288567515">"Ketuk untuk keluar dari aplikasi mengemudi."</string> @@ -1608,12 +1608,12 @@ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%2$d</xliff:g> detik."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, tablet akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, tablet akan direset ke setelan default pabrik dan semua data pengguna akan hilang."</string> <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal membuka kunci perangkat Android TV. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, perangkat Android TV akan direset ke default pabrik dan semua data pengguna akan hilang."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal saat berusaha membuka kunci ponsel. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, ponsel akan disetel ulang ke setelan default pabrik dan semua data pengguna akan hilang."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Kini tablet akan disetel ulang ke setelan default pabrik."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali gagal saat berusaha membuka kunci ponsel. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, ponsel akan direset ke setelan default pabrik dan semua data pengguna akan hilang."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha membuka kunci tablet. Kini tablet akan direset ke setelan default pabrik."</string> <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal membuka kunci perangkat Android TV. Perangkat Android TV sekarang akan direset ke default pabrik."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha untuk membuka kunci ponsel. Kini ponsel akan disetel ulang ke setelan default pabrik."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali gagal saat berusaha untuk membuka kunci ponsel. Kini ponsel akan direset ke setelan default pabrik."</string> <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah gagal <xliff:g id="NUMBER_1">%2$d</xliff:g> kali lagi, Anda akan diminta membuka kunci perangkat Android TV menggunakan akun email.\n\n Coba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string> @@ -1907,7 +1907,7 @@ <string name="app_info" msgid="6113278084877079851">"Info aplikasi"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Memulai demo..."</string> - <string name="demo_restarting_message" msgid="1160053183701746766">"Menyetel ulang perangkat..."</string> + <string name="demo_restarting_message" msgid="1160053183701746766">"Mereset perangkat..."</string> <string name="suspended_widget_accessibility" msgid="6331451091851326101">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string> <string name="conference_call" msgid="5731633152336490471">"Konferensi Telepon"</string> <string name="tooltip_popup_title" msgid="7863719020269945722">"Keterangan alat"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 400c44a4ef9c..14bfa03bb706 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -1937,7 +1937,7 @@ <item quantity="one">Un suggerimento di Compilazione automatica</item> </plurals> <string name="autofill_save_title" msgid="7719802414283739775">"Vuoi salvare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string> - <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vuoi salvare <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string> + <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Vuoi salvare la <xliff:g id="TYPE">%1$s</xliff:g> su "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Vuoi salvare <xliff:g id="TYPE_0">%1$s</xliff:g> e <xliff:g id="TYPE_1">%2$s</xliff:g> su "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>"?"</string> <string name="autofill_save_title_with_3types" msgid="6598228952100102578">"Vuoi salvare <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> e <xliff:g id="TYPE_2">%3$s</xliff:g> su "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>"?"</string> <string name="autofill_update_title" msgid="3630695947047069136">"Vuoi aggiornare su "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>"?"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 2c4274532a02..2b6d22681f52 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -1202,7 +1202,7 @@ <string name="aerr_application_repeated" msgid="7804378743218496566">"האפליקציה <xliff:g id="APPLICATION">%1$s</xliff:g> נעצרת שוב ושוב"</string> <string name="aerr_process_repeated" msgid="1153152413537954974">"האפליקציה <xliff:g id="PROCESS">%1$s</xliff:g> נעצרת שוב ושוב"</string> <string name="aerr_restart" msgid="2789618625210505419">"פתח שוב את האפליקציה"</string> - <string name="aerr_report" msgid="3095644466849299308">"משוב"</string> + <string name="aerr_report" msgid="3095644466849299308">"שליחת משוב"</string> <string name="aerr_close" msgid="3398336821267021852">"סגירה"</string> <string name="aerr_mute" msgid="2304972923480211376">"השתק עד הפעלה מחדש של המכשיר"</string> <string name="aerr_wait" msgid="3198677780474548217">"המתן"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 9f23a76de1d2..3ef51a7e6dab 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -1165,7 +1165,7 @@ <string name="capital_off" msgid="7443704171014626777">"IZKLOPLJENO"</string> <string name="checked" msgid="9179896827054513119">"potrjeno"</string> <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string> - <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z"</string> + <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z aplikacijo"</string> <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</string> <string name="whichApplicationLabel" msgid="7852182961472531728">"Izvedba dejanja"</string> <string name="whichViewApplication" msgid="5733194231473132945">"Odpiranje z aplikacijo"</string> diff --git a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java new file mode 100644 index 000000000000..ea903f2b61eb --- /dev/null +++ b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java @@ -0,0 +1,104 @@ +/* + * 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.app.backup; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.app.backup.BackupAgent.IncludeExcludeRules; +import android.app.backup.BackupManager.OperationType; +import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags; +import android.os.ParcelFileDescriptor; +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupAgentTest { + // An arbitrary user. + private static final UserHandle USER_HANDLE = new UserHandle(15); + + @Mock FullBackup.BackupScheme mBackupScheme; + + private BackupAgent mBackupAgent; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testGetIncludeExcludeRules_isMigration_returnsEmptyRules() throws Exception { + mBackupAgent = getAgentForOperationType(OperationType.MIGRATION); + + IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); + assertThat(rules).isEqualTo(IncludeExcludeRules.emptyRules()); + } + + @Test + public void testGetIncludeExcludeRules_isNotMigration_returnsRules() throws Exception { + PathWithRequiredFlags path = new PathWithRequiredFlags("path", /* requiredFlags */ 0); + Map<String, Set<PathWithRequiredFlags>> includePaths = Collections.singletonMap("test", + Collections.singleton(path)); + ArraySet<PathWithRequiredFlags> excludePaths = new ArraySet<>(); + excludePaths.add(path); + IncludeExcludeRules expectedRules = new IncludeExcludeRules(includePaths, excludePaths); + + mBackupAgent = getAgentForOperationType(OperationType.BACKUP); + when(mBackupScheme.maybeParseAndGetCanonicalExcludePaths()).thenReturn(excludePaths); + when(mBackupScheme.maybeParseAndGetCanonicalIncludePaths()).thenReturn(includePaths); + + IncludeExcludeRules rules = mBackupAgent.getIncludeExcludeRules(mBackupScheme); + assertThat(rules).isEqualTo(expectedRules); + } + + private BackupAgent getAgentForOperationType(@OperationType int operationType) { + BackupAgent agent = new TestFullBackupAgent(); + agent.onCreate(USER_HANDLE, operationType); + return agent; + } + + private static class TestFullBackupAgent extends BackupAgent { + + @Override + public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, + ParcelFileDescriptor newState) throws IOException { + // Left empty as this is a full backup agent. + } + + @Override + public void onRestore(BackupDataInput data, int appVersionCode, + ParcelFileDescriptor newState) throws IOException { + // Left empty as this is a full backup agent. + } + } +} diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index f11adef81793..e0d702e98595 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -494,7 +494,8 @@ public class TransactionParcelTests { @Override public void scheduleCreateBackupAgent(ApplicationInfo applicationInfo, - CompatibilityInfo compatibilityInfo, int i, int userId) throws RemoteException { + CompatibilityInfo compatibilityInfo, int i, int userId, int operatioType) + throws RemoteException { } @Override diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index 801cd4ddb94e..af02b7bdbd90 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -27,6 +27,7 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.navigationBars; import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; @@ -40,8 +41,11 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.Context; @@ -124,7 +128,7 @@ public class InsetsControllerTest { } mTestClock = new OffsettableClock(); mTestHandler = new TestHandler(null, mTestClock); - mTestHost = new TestHost(mViewRoot); + mTestHost = spy(new TestHost(mViewRoot)); mController = new InsetsController(mTestHost, (controller, type) -> { if (type == ITYPE_IME) { return new InsetsSourceConsumer(type, controller.getState(), @@ -745,6 +749,99 @@ public class InsetsControllerTest { }); } + @Test + public void testInsetsChangedCount_controlSystemBars() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + prepareControls(); + + // Hiding visible system bars should only causes insets change once for each bar. + clearInvocations(mTestHost); + mController.hide(statusBars() | navigationBars()); + verify(mTestHost, times(2)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after hiding system bars. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Showing invisible system bars should only causes insets change once for each bar. + clearInvocations(mTestHost); + mController.show(statusBars() | navigationBars()); + verify(mTestHost, times(2)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after showing system bars. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + }); + } + + @Test + public void testInsetsChangedCount_controlIme() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + prepareControls(); + + // Showing invisible ime should only causes insets change once. + clearInvocations(mTestHost); + mController.show(ime(), true /* fromIme */); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after showing ime. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Hiding visible ime should only causes insets change once. + clearInvocations(mTestHost); + mController.hide(ime()); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Sending the same insets state should not cause insets change. + // This simulates the callback from server after hiding ime. + clearInvocations(mTestHost); + mController.onStateChanged(mController.getState()); + verify(mTestHost, never()).notifyInsetsChanged(); + }); + } + + @Test + public void testInsetsChangedCount_onStateChanged() { + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final InsetsState localState = mController.getState(); + + // Changing status bar frame should cause notifyInsetsChanged. + clearInvocations(mTestHost); + InsetsState newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_STATUS_BAR).getFrame().bottom++; + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Changing status bar visibility should cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_STATUS_BAR).setVisible(false); + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + + // Changing invisible IME frame should not cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_IME).getFrame().top--; + mController.onStateChanged(newState); + verify(mTestHost, never()).notifyInsetsChanged(); + + // Changing IME visibility should cause notifyInsetsChanged. + clearInvocations(mTestHost); + newState = new InsetsState(localState, true /* copySources */); + newState.getSource(ITYPE_IME).setVisible(true); + mController.onStateChanged(newState); + verify(mTestHost, times(1)).notifyInsetsChanged(); + }); + } + private void waitUntilNextFrame() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT, @@ -777,7 +874,7 @@ public class InsetsControllerTest { return controls; } - private static class TestHost extends ViewRootInsetsControllerHost { + public static class TestHost extends ViewRootInsetsControllerHost { private InsetsState mModifiedState = new InsetsState(); diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index b3c82631011a..602ccfeca2f2 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -143,6 +143,7 @@ applications that come with the platform <permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> <permission name="android.permission.PACKAGE_USAGE_STATS" /> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" /> + <permission name="android.permission.MODIFY_AUDIO_ROUTING" /> <!-- For permission hub 2 debugging only --> <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> diff --git a/framework-jarjar-rules.txt b/framework-jarjar-rules.txt index d8af726ffa72..70dedb8179b0 100644 --- a/framework-jarjar-rules.txt +++ b/framework-jarjar-rules.txt @@ -1,2 +1,6 @@ rule android.hidl.** android.internal.hidl.@1 rule android.net.wifi.WifiAnnotations* android.internal.wifi.WifiAnnotations@1 + +# Hide media mainline module implementation classes to avoid collisions with +# app-bundled ExoPlayer classes. +rule com.google.android.exoplayer2.** android.media.internal.exo.@1 diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java index b3103fd516dd..0452933328e2 100644 --- a/graphics/java/android/graphics/HardwareRenderer.java +++ b/graphics/java/android/graphics/HardwareRenderer.java @@ -634,6 +634,19 @@ public class HardwareRenderer { } /** + * Sets the colormode with the desired SDR white point. + * + * The white point only applies if the color mode is an HDR mode + * + * @hide + */ + public void setColorMode(@ActivityInfo.ColorMode int colorMode, float whitePoint) { + nSetSdrWhitePoint(mNativeProxy, whitePoint); + mColorMode = colorMode; + nSetColorMode(mNativeProxy, colorMode); + } + + /** * Blocks until all previously queued work has completed. * * TODO: Only used for draw finished listeners, but the FrameCompleteCallback does that @@ -1227,6 +1240,8 @@ public class HardwareRenderer { private static native void nSetColorMode(long nativeProxy, int colorMode); + private static native void nSetSdrWhitePoint(long nativeProxy, float whitePoint); + private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size); private static native void nDestroy(long nativeProxy, long rootRenderNode); diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 446e81e65bb8..ba44d056dda3 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -78,6 +78,7 @@ bool Properties::isolatedProcess = false; int Properties::contextPriority = 0; int Properties::defaultRenderAhead = -1; +float Properties::defaultSdrWhitePoint = 200.f; bool Properties::load() { bool prevDebugLayersUpdates = debugLayersUpdates; diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index c8f6b3b7ff99..85a0f4aa7809 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -249,6 +249,8 @@ public: static int defaultRenderAhead; + static float defaultSdrWhitePoint; + private: static ProfileType sProfileType; static bool sDisableProfileBars; diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index 7d6875f59d17..fc594da19708 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -223,6 +223,11 @@ static void android_view_ThreadedRenderer_setColorMode(JNIEnv* env, jobject claz proxy->setColorMode(static_cast<ColorMode>(colorMode)); } +static void android_view_ThreadedRenderer_setSdrWhitePoint(JNIEnv* env, jobject clazz, + jlong proxyPtr, jfloat sdrWhitePoint) { + Properties::defaultSdrWhitePoint = sdrWhitePoint; +} + static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz, jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) { LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE, @@ -671,6 +676,7 @@ static const JNINativeMethod gMethods[] = { {"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry}, {"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque}, {"nSetColorMode", "(JI)V", (void*)android_view_ThreadedRenderer_setColorMode}, + {"nSetSdrWhitePoint", "(JF)V", (void*)android_view_ThreadedRenderer_setSdrWhitePoint}, {"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame}, {"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy}, {"nRegisterAnimatingRenderNode", "(JJ)V", diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index eff34a83af1b..87512f0354c8 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -26,6 +26,7 @@ #include <algorithm> #include <cmath> +#include <Properties.h> namespace android { namespace uirenderer { @@ -344,13 +345,9 @@ SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) { static_cast<uint8_t>(rgb.b * 255)); } -// Note that SkColorSpace doesn't have the notion of an unspecified SDR white -// level. -static constexpr float kDefaultSDRWhiteLevel = 150.f; - skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level) { if (sdr_white_level <= 0.f) { - sdr_white_level = kDefaultSDRWhiteLevel; + sdr_white_level = Properties::defaultSdrWhitePoint; } // The generic PQ transfer function produces normalized luminance values i.e. // the range 0-1 represents 0-10000 nits for the reference display, but we diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 6fa378724240..2b3f420cd834 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -1616,9 +1616,9 @@ public class MediaRouter { Drawable mIcon; // playback information int mPlaybackType = PLAYBACK_TYPE_LOCAL; - int mVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; - int mVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; - int mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; + int mVolumeMax = DEFAULT_PLAYBACK_MAX_VOLUME; + int mVolume = DEFAULT_PLAYBACK_VOLUME; + int mVolumeHandling = PLAYBACK_VOLUME_VARIABLE; int mPlaybackStream = AudioManager.STREAM_MUSIC; VolumeCallbackInfo mVcb; Display mPresentationDisplay; @@ -1722,6 +1722,21 @@ public class MediaRouter { */ public final static int PLAYBACK_VOLUME_VARIABLE = 1; + /** + * Default playback max volume if not set. + * Hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC] + * + * @see #getVolumeMax() + */ + private static final int DEFAULT_PLAYBACK_MAX_VOLUME = 15; + + /** + * Default playback volume if not set. + * + * @see #getVolume() + */ + private static final int DEFAULT_PLAYBACK_VOLUME = DEFAULT_PLAYBACK_MAX_VOLUME; + RouteInfo(RouteCategory category) { mCategory = category; mDeviceType = DEVICE_TYPE_UNKNOWN; @@ -2430,13 +2445,13 @@ public class MediaRouter { } return; } - if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { + if (mPlaybackType == PLAYBACK_TYPE_REMOTE) { int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED; switch (mVolumeHandling) { - case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE: + case PLAYBACK_VOLUME_VARIABLE: volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE; break; - case RemoteControlClient.PLAYBACK_VOLUME_FIXED: + case PLAYBACK_VOLUME_FIXED: default: break; } diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 8bf462c5a5cf..70bd1609ddbd 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -19,6 +19,7 @@ package android.media.session; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.Activity; import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; @@ -105,6 +106,7 @@ public final class MediaSession { * * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16; /** diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index 3c0b955119a6..86ac3e477dc4 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -39,6 +39,14 @@ package android.media { } +package android.media.session { + + public final class MediaSession { + field public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 65536; // 0x10000 + } + +} + package android.os { public class Binder implements android.os.IBinder { diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 844e929774a1..10887fabb5c7 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -11575,6 +11575,9 @@ package android.webkit { public interface PacProcessor { method @Nullable public String findProxyForUrl(@NonNull String); method @NonNull public static android.webkit.PacProcessor getInstance(); + method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long); + method public default long getNetworkHandle(); + method public default void releasePacProcessor(); method public boolean setProxyScript(@NonNull String); } @@ -11714,6 +11717,7 @@ package android.webkit { method public android.webkit.CookieManager getCookieManager(); method public android.webkit.GeolocationPermissions getGeolocationPermissions(); method @NonNull public default android.webkit.PacProcessor getPacProcessor(); + method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long); method public android.webkit.ServiceWorkerController getServiceWorkerController(); method public android.webkit.WebViewFactoryProvider.Statics getStatics(); method @Deprecated public android.webkit.TokenBindingService getTokenBindingService(); diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java index 1e4c7cac4404..52d2b3c919d9 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java @@ -376,8 +376,12 @@ public abstract class Tile implements Parcelable { * Check whether tile only has primary profile. */ public boolean isPrimaryProfileOnly() { - String profile = mMetaData != null - ? mMetaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL; + return isPrimaryProfileOnly(mMetaData); + } + + static boolean isPrimaryProfileOnly(Bundle metaData) { + String profile = metaData != null + ? metaData.getString(META_DATA_KEY_PROFILE) : PROFILE_ALL; profile = (profile != null ? profile : PROFILE_ALL); return TextUtils.equals(profile, PROFILE_PRIMARY); } diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java index ace50f30663d..49f6bd8c3334 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java @@ -339,6 +339,16 @@ public class TileUtils { private static void loadTile(UserHandle user, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, Intent intent, Bundle metaData, ComponentInfo componentInfo) { + // Skip loading tile if the component is tagged primary_profile_only but not running on + // the current user. + if (user.getIdentifier() != ActivityManager.getCurrentUser() + && Tile.isPrimaryProfileOnly(componentInfo.metaData)) { + Log.w(LOG_TAG, "Found " + componentInfo.name + " for intent " + + intent + " is primary profile only, skip loading tile for uid " + + user.getIdentifier()); + return; + } + String categoryKey = defaultCategory; // Load category if ((metaData == null || !metaData.containsKey(EXTRA_CATEGORY_KEY)) diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java index 2fb2481ac117..df98b1717b9b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java @@ -108,8 +108,8 @@ public class TestAccessPointBuilder { public TestAccessPointBuilder setActive(boolean active) { if (active) { mNetworkInfo = new NetworkInfo( - ConnectivityManager.TYPE_DUMMY, - ConnectivityManager.TYPE_DUMMY, + ConnectivityManager.TYPE_WIFI, + ConnectivityManager.TYPE_WIFI, "TestNetwork", "TestNetwork"); } else { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index 9b4b97e7f55d..176905305506 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -17,11 +17,14 @@ package com.android.settingslib.drawer; import static com.android.settingslib.drawer.TileUtils.IA_SETTINGS_ACTION; +import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_ICON_URI; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY; import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY_URI; +import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL; +import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY; import static com.google.common.truth.Truth.assertThat; @@ -189,7 +192,7 @@ public class TileUtilsTest { List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, - URI_GET_SUMMARY, "my title", 0); + URI_GET_SUMMARY, "my title", 0, PROFILE_ALL); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) @@ -211,7 +214,7 @@ public class TileUtilsTest { List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, - URI_GET_SUMMARY, null, 123); + URI_GET_SUMMARY, null, 123, PROFILE_ALL); info.add(resolveInfo); when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) @@ -235,7 +238,7 @@ public class TileUtilsTest { List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, - URI_GET_SUMMARY, null, 123); + URI_GET_SUMMARY, null, 123, PROFILE_ALL); resolveInfo.activityInfo.packageName = "com.android.settings"; resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings"; info.add(resolveInfo); @@ -258,7 +261,7 @@ public class TileUtilsTest { final List<Tile> outTiles = new ArrayList<>(); final List<ResolveInfo> info = new ArrayList<>(); final ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, - URI_GET_SUMMARY, null, 123); + URI_GET_SUMMARY, null, 123, PROFILE_ALL); resolveInfo.activityInfo.packageName = "com.android.settings"; resolveInfo.activityInfo.applicationInfo.packageName = "com.android.settings"; info.add(resolveInfo); @@ -290,7 +293,7 @@ public class TileUtilsTest { List<Tile> outTiles = new ArrayList<>(); List<ResolveInfo> info = new ArrayList<>(); ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, - URI_GET_SUMMARY, null, 123); + URI_GET_SUMMARY, null, 123, PROFILE_ALL); resolveInfo.activityInfo.metaData .putBoolean(TileUtils.META_DATA_PREFERENCE_ICON_TINTABLE, true); info.add(resolveInfo); @@ -327,6 +330,26 @@ public class TileUtilsTest { assertThat(outTiles).hasSize(2); } + @Test + public void loadTilesForAction_isPrimaryProfileOnly_shouldSkipNonPrimaryUserTiles() { + Map<Pair<String, String>, Tile> addedCache = new ArrayMap<>(); + List<Tile> outTiles = new ArrayList<>(); + List<ResolveInfo> info = new ArrayList<>(); + ResolveInfo resolveInfo = newInfo(true, null /* category */, null, URI_GET_ICON, + URI_GET_SUMMARY, null, 123, PROFILE_PRIMARY); + info.add(resolveInfo); + + when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) + .thenReturn(info); + when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), + anyInt())).thenReturn(info); + + TileUtils.loadTilesForAction(mContext, new UserHandle(10), IA_SETTINGS_ACTION, + addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */); + + assertThat(outTiles).isEmpty(); + } + public static ResolveInfo newInfo(boolean systemApp, String category) { return newInfo(systemApp, category, null); } @@ -337,14 +360,14 @@ public class TileUtilsTest { private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint, String iconUri, String summaryUri) { - return newInfo(systemApp, category, keyHint, iconUri, summaryUri, null, 0); + return newInfo(systemApp, category, keyHint, iconUri, summaryUri, null, 0, PROFILE_ALL); } private static ResolveInfo newInfo(boolean systemApp, String category, String keyHint, - String iconUri, String summaryUri, String title, int titleResId) { + String iconUri, String summaryUri, String title, int titleResId, String profile) { final Bundle metaData = newMetaData(category, keyHint, iconUri, summaryUri, title, - titleResId); + titleResId, profile); final ResolveInfo info = new ResolveInfo(); info.system = systemApp; @@ -358,6 +381,7 @@ public class TileUtilsTest { info.providerInfo.packageName = "abc"; info.providerInfo.name = "456"; info.providerInfo.authority = "auth"; + info.providerInfo.metaData = metaData; ShadowTileUtils.setMetaData(metaData); info.providerInfo.applicationInfo = new ApplicationInfo(); @@ -369,7 +393,7 @@ public class TileUtilsTest { } private static Bundle newMetaData(String category, String keyHint, String iconUri, - String summaryUri, String title, int titleResId) { + String summaryUri, String title, int titleResId, String profile) { final Bundle metaData = new Bundle(); metaData.putString("com.android.settings.category", category); metaData.putInt(META_DATA_PREFERENCE_ICON, 314159); @@ -388,6 +412,9 @@ public class TileUtilsTest { } else if (title != null) { metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE, title); } + if (profile != null) { + metaData.putString(META_DATA_KEY_PROFILE, profile); + } return metaData; } diff --git a/packages/SystemUI/res-product/values-in/strings.xml b/packages/SystemUI/res-product/values-in/strings.xml index 2e0580f568f9..1451e2c063c9 100644 --- a/packages/SystemUI/res-product/values-in/strings.xml +++ b/packages/SystemUI/res-product/values-in/strings.xml @@ -26,10 +26,10 @@ <string name="keyguard_missing_sim_message" product="tablet" msgid="5018086454277963787">"Tidak ada kartu SIM dalam tablet."</string> <string name="keyguard_missing_sim_message" product="default" msgid="7053347843877341391">"Tidak ada kartu SIM dalam ponsel."</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"Kode PIN tidak cocok"</string> - <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> - <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> - <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> - <string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, tablet ini akan direset, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan direset, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Tablet ini akan direset, sehingga semua datanya akan dihapus."</string> + <string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Ponsel ini akan direset, sehingga semua datanya akan dihapus."</string> <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="7325071812832605911">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya yang tidak berhasil, pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="8509811676952707883">"Anda telah <xliff:g id="NUMBER">%d</xliff:g> kali berupaya membuka kunci tablet dengan tidak benar. Pengguna ini akan dihapus, sehingga semua data pengguna akan dihapus."</string> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 308fd88ee6cd..ee8700261db5 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hou aan/af-skakelaar in om nuwe kontroles te sien"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Voeg kontroles by"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Wysig kontroles"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Gebruik eenhandmodus"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Swiep van die onderkant van die skerm af op of tik enige plek bo die program om uit te gaan"</string> </resources> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index f2bf5778b42f..03eb39659ef3 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"አዲስ መቆጣጠሪያዎችን ለማየት የኃይል አዝራር ይያዙ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"መቆጣጠሪያዎችን አክል"</string> <string name="controls_menu_edit" msgid="890623986951347062">"መቆጣጠሪያዎችን ያርትዑ"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ባለአንድ እጅ ሁነታን በመጠቀም ላይ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ለመውጣት ከማያው ግርጌ ወደ ላይ ይጥረጉ ወይም ከመተግበሪያው በላይ ማንኛውም ቦታ ላይ መታ ያድርጉ"</string> </resources> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 36280e716c4e..95d54a2386dd 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1108,4 +1108,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"اضغط مع الاستمرار على زر التشغيل لعرض عناصر التحكّم الجديدة."</string> <string name="controls_menu_add" msgid="4447246119229920050">"إضافة عناصر تحكّم"</string> <string name="controls_menu_edit" msgid="890623986951347062">"تعديل عناصر التحكّم"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"استخدام وضع \"التصفح بيد واحدة\""</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"للخروج، مرِّر سريعًا من أسفل الشاشة إلى أعلاها أو انقر في أي مكان فوق التطبيق."</string> </resources> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index a4cc17b822d5..3023a27b15b4 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"বেটাৰি সঞ্চয়কাৰী অন হৈ আছে"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"কাৰ্যদক্ষতা আৰু নেপথ্য ডেটা হ্ৰাস কৰে"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"বেটাৰি সঞ্চয়কাৰী অফ কৰক"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিংৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>এ আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিংৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা সকলো তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ জৰিয়তে ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে ?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"নতুন নিয়ন্ত্ৰণসমূহ চাবলৈ পাৱাৰৰ বুটামটো ধৰি ৰাখক"</string> <string name="controls_menu_add" msgid="4447246119229920050">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string> <string name="controls_menu_edit" msgid="890623986951347062">"নিয়ন্ত্ৰণসমূহ সম্পাদনা কৰক"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"এখন হাতেৰে ব্যৱহাৰ কৰা ম’ড ব্যৱহাৰ কৰিবলৈ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"বাহিৰ হ’বলৈ স্ক্রীনখনৰ একেবাৰে তলৰ পৰা ওপৰলৈ ছোৱাইপ কৰক অথবা এপ্টোৰ ওপৰত যিকোনো ঠাইত টিপক"</string> </resources> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 9443ba8ac22c..3c8e04b7ba35 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Yeni nizamlayıcıları görmək üçün yandırıb-söndürmə düyməsinə basıb saxlayın"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Nizamlayıcılar əlavə edin"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Nizamlayıcıları redaktə edin"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bir əlli rejimdən istifadə edilir"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Çıxmaq üçün ekranın aşağısından yuxarıya doğru sürüşdürün və ya tətbiqin yuxarısında istənilən yerə toxunun"</string> </resources> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 5b8c44599eed..4b400eb479c9 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da biste videli nove kontrole"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Izmeni kontrole"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korišćenje režima jednom rukom"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Da biste izašli, prevucite nagore od dna ekrana ili dodirnite bilo gde iznad aplikacije"</string> </resources> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 6ee51682fe85..f1064fb7b1d7 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Каб убачыць новыя элементы кіравання, утрымлівайце кнопку сілкавання націснутай"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Дадаць элементы кіравання"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Змяніць элементы кіравання"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Выкарыстоўваецца рэжым кіравання адной рукой"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Каб выйсці, правядзіце па экране пальцам знізу ўверх або націсніце ў любым месцы над праграмай"</string> </resources> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index c7bb3d08579c..8ba2a1e51769 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Задръжте бутона за захранване, за да видите новите контроли"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Добавяне на контроли"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Редактиране на контролите"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Използване на режима за работа с една ръка"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"За изход прекарайте пръст нагоре от долната част на екрана или докоснете произволно място над приложението"</string> </resources> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 42e7523aef81..5861c44c1cbb 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"নতুন কন্ট্রোল দেখতে পাওয়ার বোতাম টিপে ধরে থাকুন"</string> <string name="controls_menu_add" msgid="4447246119229920050">"কন্ট্রোল যোগ করুন"</string> <string name="controls_menu_edit" msgid="890623986951347062">"কন্ট্রোল এডিট করুন"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 16a1aa615c9b..984cbebd42eb 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite dugme za uključivanje da vidite nove kontrole"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korištenje načina rada jednom rukom"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Da izađete, prevucite s dna ekrana prema gore ili dodirnite bilo gdje iznad aplikacije"</string> </resources> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index fdcec987f438..b8c41efa7813 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén premut el botó d\'engegada per veure controls nous"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Afegeix controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edita els controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"S\'està utilitzant el mode d\'una mà"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Per sortir, llisca cap amunt des de la part inferior de la pantalla o toca qualsevol lloc a sobre de l\'aplicació"</string> </resources> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index ab3b4fb2659c..f946cc4f9552 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Nové ovládací prvky zobrazíte podržením vypínače"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Přidat ovládací prvky"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Upravit ovládací prvky"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Používáte režim jedné ruky"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Režim ukončíte, když přejedete prstem z dolní části obrazovky nahoru nebo klepnete kamkoli nad aplikaci"</string> </resources> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 0fc9b9495388..a6de8a618f23 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold afbryderknappen nede for at se nye betjeningselementer"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Tilføj styring"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Rediger styring"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Brug af enhåndstilstand"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Du kan afslutte ved at stryge opad fra bunden af skærmen eller trykke et vilkårligt sted over appen"</string> </resources> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index a6b137a8e9e5..372cc1166fce 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Energiesparmodus ist aktiviert"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduzierung der Leistung und Hintergrunddaten"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Energiesparmodus deaktivieren"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"Die App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"Die App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise angezeigte Passwörter und Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Aufnahme oder Stream starten?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Aufnehmen oder Streamen mit der App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" starten?"</string> @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Zum Anzeigen der Karten für neue Geräte Ein-/Aus-Taste gedrückt halten"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Steuerelemente hinzufügen"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Steuerelemente bearbeiten"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index bdd19a18b2dd..b4673476bad5 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Πατήστε το κουμπί λειτουργίας για να δείτε νέα στοιχεία ελέγχου."</string> <string name="controls_menu_add" msgid="4447246119229920050">"Προσθήκη στοιχείων ελέγχου"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Επεξεργασία στοιχείων ελέγχου"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Χρήση λειτουργίας ενός χεριού"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Για έξοδο, σύρετε προς τα πάνω από το κάτω μέρος της οθόνης ή πατήστε οπουδήποτε πάνω από την εφαρμογή."</string> </resources> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 68a8d30477f6..7fa7f83c5f12 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Battery Saver is on"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduces performance and background data"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index e9856af6cb1e..f73dad3a8bef 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Battery Saver is on"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduces performance and background data"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 68a8d30477f6..7fa7f83c5f12 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Battery Saver is on"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduces performance and background data"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 68a8d30477f6..7fa7f83c5f12 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Battery Saver is on"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduces performance and background data"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Turn off Battery Saver"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information, such as passwords, payment details, photos, messages and audio that you play."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> </resources> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index eacef2624b05..6140bf1eea3d 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold Power button to see new controls"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Add controls"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit controls"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Using one-handed mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"To exit, swipe up from the bottom of the screen or tap anywhere above the app"</string> </resources> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 94a464bb6afa..6818116ec9b5 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén presionado el botón de encendido para ver los nuevos controles"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Agregar controles"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Cómo usar el Modo de una mano"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para salir, desliza el dedo hacia arriba desde la parte inferior de la pantalla o presiona cualquier parte arriba de la app"</string> </resources> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 0e7d376e5884..f09a0d24b26e 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -502,10 +502,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Ahorro de batería activado"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduce el rendimiento y los datos en segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desactivar Ahorro de batería"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que se muestre en pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestre en pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tendrá acceso a toda la información que se muestre en la pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestre en la pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Empezar a grabar o enviar contenido?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Quieres iniciar la grabación o el envío de contenido con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Iniciar grabación o el envío de contenido en <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"No volver a mostrar"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén pulsado el botón de encendido para ver los controles nuevos"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Añadir controles"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utilizar el modo una mano"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para salir, desliza dos dedos hacia arriba desde la parte inferior de la pantalla o toca cualquier zona que haya encima de la aplicación."</string> </resources> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index fc9c73bb10bf..6236f251f55d 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Uute juhtelementide vaatamiseks hoidke all toitenuppu"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Lisa juhtelemente"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Muuda juhtelemente"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ühekäerežiimi kasutamine"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Väljumiseks pühkige ekraani alaosast üles või puudutage ekraani rakenduse kohal"</string> </resources> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 041beab2e74c..167a09c71ce3 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Eduki sakatuta etengailua kontrolatzeko aukera berriak ikusteko"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Gehitu aukerak"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editatu aukerak"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Esku bakarreko modua erabiltzea"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ateratzeko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainean, edonon"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 05e076f55a12..055505200cc2 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -742,7 +742,7 @@ <string name="feedback_promoted" msgid="8075757485407091976">"سیستمْ این اعلان را ارتقا داده است."</string> <string name="feedback_demoted" msgid="5848066008939031913">"سیستمْ این اعلان را تنزل داده است."</string> <string name="feedback_prompt" msgid="2278631214125128281">"این مورد درست بود؟"</string> - <string name="feedback_response" msgid="4671729244976641339">"از بازخورد شما سپاسگزاریم!"</string> + <string name="feedback_response" msgid="4671729244976641339">"از بازخورد شما سپاسگذاریم!"</string> <string name="feedback_ok" msgid="6481426753298857144">"تأیید"</string> <string name="notification_channel_controls_opened_accessibility" msgid="6111817750774381094">"کنترلهای اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> باز شد"</string> <string name="notification_channel_controls_closed_accessibility" msgid="1561909368876911701">"کنترلهای اعلان برای <xliff:g id="APP_NAME">%1$s</xliff:g> بسته شد"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"برای دیدن کنترلهای جدید، دکمه روشن/خاموش را پایین نگه دارید"</string> <string name="controls_menu_add" msgid="4447246119229920050">"افزودن کنترلها"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ویرایش کنترلها"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"استفاده از «حالت تک حرکت»"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"برای خارج شدن، از پایین صفحهنمایش تند بهطرف بالا بکشید یا در هر جایی از بالای برنامه که میخواهید ضربه بزنید"</string> </resources> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 4fccaaca57f2..ec9bbc4a8929 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Paina virtapainiketta pitkään nähdäksesi uudet säätimet"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Lisää säätimiä"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Muokkaa säätimiä"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Yhden käden moodin käyttö"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Poistu pyyhkäisemällä ylös näytön alareunasta tai napauttamalla sovelluksen yllä"</string> </resources> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 4e2074c34a88..6c5387f63eda 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Économiseur de pile activé"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Réduire les performances et de fond"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver la fonction Économiseur de pile"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et l\'audio que vous faites jouer."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toute l\'information visible sur votre écran ou qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service offrant cette fonction aura accès à toute l\'information qui est visible sur votre écran ou sur ce qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Commencer à enregistrer ou à diffuser?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Maintenez enfoncé l\'interrupteur pour afficher les nouvelles commandes"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utiliser le mode Une main"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pour quitter, balayez l\'écran du bas vers le haut, ou touchez n\'importe où sur l\'écran en haut de l\'application"</string> </resources> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index fedec563edcf..3a2ae07bc64d 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Économiseur de batterie activé"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Limite les performances et les données en arrière-plan."</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Désactiver l\'économiseur de batterie"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Par exemple, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore vos contenus audio lus."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil pendant un enregistrement ou une diffusion de contenu. Il peut s\'agir de mots de passe, données de paiement, photos, messages ou encore contenus audio lus."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service qui fournit cette fonction aura accès à toutes les informations visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou d\'une diffusion de contenu. Cela comprend, entre autres, vos mots de passe, vos données de paiement, vos photos, vos messages ou encore les contenus audio que vous lisez."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Démarrer l\'enregistrement ou la diffusion ?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Démarrer l\'enregistrement ou la diffusion avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Appuyez de manière prolongée sur le bouton Marche/Arrêt pour afficher les nouvelles commandes"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Ajouter des commandes"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Modifier des commandes"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utiliser le mode une main"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pour quitter, balayez l\'écran de bas en haut ou appuyez n\'importe où au-dessus de l\'application"</string> </resources> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index c1b9024e8b44..25c7b4bfab59 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantén premido o botón de acendido para ver os novos controis"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Engadir controis"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controis"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como se usa o modo dunha soa man?"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para saír, pasa o dedo cara arriba desde a parte inferior da pantalla ou toca calquera lugar da zona situada encima da aplicación"</string> </resources> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 9c2f71790fb0..17cc5a45aeb9 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"નવા નિયંત્રણ જોવા માટે પાવર બટનને દબાવી રાખો"</string> <string name="controls_menu_add" msgid="4447246119229920050">"નિયંત્રણો ઉમેરો"</string> <string name="controls_menu_edit" msgid="890623986951347062">"નિયંત્રણોમાં ફેરફાર કરો"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index cc2faa2a598c..97ae7b6e8926 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1086,4 +1086,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"नए कंट्रोल देखने के लिए पावर बटन दबाकर रखें"</string> <string name="controls_menu_add" msgid="4447246119229920050">"कंट्राेल जोड़ें"</string> <string name="controls_menu_edit" msgid="890623986951347062">"कंट्रोल मेन्यू में बदलाव करें"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"वन-हैंडेड मोड का इस्तेमाल करें"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"इसे बंद करने के लिए, स्क्रीन के सबसे निचले हिस्से से ऊपर की ओर स्वाइप करें या ऐप्लिकेशन के आइकॉन के ऊपर कहीं भी टैप करें"</string> </resources> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 90251995002d..9e17735ef18d 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -505,10 +505,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Štednja baterije je uključena"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Smanjuje količinu rada i pozadinske podatke"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Isključite Štednju baterije"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkcionalnost imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Započeti snimanje ili emitiranje?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"Započeti snimanje ili emitiranja pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"Započeti snimanje ili emitiranje pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Ne prikazuj ponovo"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Zadržite tipku za uključivanje/isključivanje za prikaz novih kontrola"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrole"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrole"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korištenje načina rada jednom rukom"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Za izlaz prijeđite prstom od dna zaslona prema gore ili dodirnite bio gdje iznad aplikacije"</string> </resources> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 689d86960c88..804587f9bdcd 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Az új vezérlők megtekintéséhez tartsa nyomva a bekapcsológombot"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Vezérlők hozzáadása"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Vezérlők szerkesztése"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Egykezes mód használata"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"A kilépéshez csúsztasson felfelé a képernyő aljáról, vagy koppintson az alkalmazás felett a képernyő bármelyik részére"</string> </resources> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index a574f26a514d..08ef489901ee 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Սեղմած պահեք սնուցման կոճակը՝ կառավարման նոր տարրերը տեսնելու համար։"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Ավելացնել կառավարման տարրեր"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Փոփոխել կառավարման տարրերը"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ինչպես օգտվել մեկ ձեռքի ռեժիմից"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Դուրս գալու համար մատը սահեցրեք էկրանի ներքևից վերև կամ հպեք հավելվածի վերևում որևէ տեղ։"</string> </resources> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 7cc1b898dedb..ba9eca3f0de9 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -855,7 +855,7 @@ </string-array> <string name="menu_ime" msgid="5677467548258017952">"Pengalih keyboard"</string> <string name="save" msgid="3392754183673848006">"Simpan"</string> - <string name="reset" msgid="8715144064608810383">"Setel ulang"</string> + <string name="reset" msgid="8715144064608810383">"Reset"</string> <string name="adjust_button_width" msgid="8313444823666482197">"Sesuaikan lebar tombol"</string> <string name="clipboard" msgid="8517342737534284617">"Papan klip"</string> <string name="accessibility_key" msgid="3471162841552818281">"Tombol navigasi khusus"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Tahan Tombol daya untuk melihat kontrol baru"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Tambahkan kontrol"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit kontrol"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Menggunakan mode satu tangan"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Untuk keluar, geser layar dari bawah ke atas atau ketuk di mana saja di atas aplikasi"</string> </resources> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 8b686b8deb96..629581346d46 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Haltu aflrofanum inni til að sjá nýjar stýringar"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Bæta við stýringum"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Breyta stýringum"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Notkun stillingar fyrir eina hönd"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Til að loka skaltu strjúka upp frá neðri hluta skjásins eða ýta hvar sem er fyrir ofan forritið"</string> </resources> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 35742fd4d4db..ef862cb0f919 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Tieni premuto il tasto di accensione per visualizzare i nuovi controlli"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Aggiungi controlli"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Modifica controlli"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Usare la modalità one-hand"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Per uscire, scorri verso l\'alto dalla parte inferiore dello schermo oppure tocca un punto qualsiasi sopra l\'app"</string> </resources> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 1029bb2042db..358946d69472 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -508,7 +508,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"תכונת החיסכון בסוללה פועלת"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"מפחית את הביצועים ונתונים ברקע"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"כיבוי תכונת החיסכון בסוללה"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"לאפליקציה <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או העברה (cast). זה כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"לאפליקציית <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> תהיה גישה לכל המידע הגלוי במסך שלך ולכל תוכן שמופעל במכשיר שלך בזמן הקלטה או העברה (casting). המידע הזה כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"לשירות שמספק את הפונקציה הזו תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או העברה (cast). זה כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"להתחיל להקליט או להעביר (cast)?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"להתחיל להקליט או להעביר (cast) באמצעות <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -522,7 +522,7 @@ <string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ניקוי כל ההתראות השקטות"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"התראות הושהו על ידי מצב \'נא לא להפריע\'"</string> - <string name="media_projection_action_text" msgid="3634906766918186440">"התחל כעת"</string> + <string name="media_projection_action_text" msgid="3634906766918186440">"כן, אפשר להתחיל"</string> <string name="empty_shade_text" msgid="8935967157319717412">"אין התראות"</string> <string name="profile_owned_footer" msgid="2756770645766113964">"ייתכן שהפרופיל נתון למעקב"</string> <string name="vpn_footer" msgid="3457155078010607471">"ייתכן שהרשת נמצאת במעקב"</string> @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ניתן ללחוץ על לחצן ההפעלה כדי להציג פקדים חדשים"</string> <string name="controls_menu_add" msgid="4447246119229920050">"הוספת פקדים"</string> <string name="controls_menu_edit" msgid="890623986951347062">"עריכת פקדים"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"איך להשתמש במצב שימוש ביד אחת"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"כדי לצאת, יש להחליק למעלה מתחתית המסך או להקיש במקום כלשהו במסך מעל האפליקציה"</string> </resources> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index fedd9bb7ffc0..9cb872bf1fab 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -502,10 +502,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"バッテリー セーバー ON"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"パフォーマンスとバックグラウンドデータを制限します"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"バッテリー セーバーを OFF"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>は、記録中やキャスト中に画面上に表示またはデバイスから再生されるすべての情報にアクセスできます。これには、パスワード、お支払いの詳細、写真、メッセージ、再生される音声などの情報が含まれます。"</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"この機能を提供するサービスは、記録中やキャスト中に画面上に表示またはデバイスから再生されるすべての情報にアクセスできます。これには、パスワード、お支払いの詳細、写真、メッセージ、再生される音声などの情報が含まれます。"</string> - <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"記録やキャストを開始しますか?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で記録やキャストを開始しますか?"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> は、録画中やキャスト中に画面に表示されたり、デバイスで再生されるすべての情報にアクセスできます。これには、パスワード、お支払いの詳細、写真、メッセージ、再生される音声などが含まれます。"</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"この機能を提供するサービスは、録画中やキャスト中に画面に表示されたり、デバイスで再生されるすべての情報にアクセスできます。これには、パスワード、お支払いの詳細、写真、メッセージ、再生される音声などが含まれます。"</string> + <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"録画やキャストを開始しますか?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> で録画やキャストを開始しますか?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"次回から表示しない"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"電源ボタンを長押しすると、新しいコントロールが表示されます"</string> <string name="controls_menu_add" msgid="4447246119229920050">"コントロールを追加"</string> <string name="controls_menu_edit" msgid="890623986951347062">"コントロールを編集"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"片手モードの使用"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"終了するには、画面を下から上にスワイプするか、アプリの任意の場所をタップします"</string> </resources> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 5c55112ea1fd..ef6ff128ed09 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ხანგრძლივად დააჭირეთ ჩართვის ღილაკს მართვის ახალი საშუალებების სანახავად"</string> <string name="controls_menu_add" msgid="4447246119229920050">"მართვის საშუალებების დამატება"</string> <string name="controls_menu_edit" msgid="890623986951347062">"მართვის საშუალებათა რედაქტირება"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ცალი ხელის რეჟიმის გამოყენება"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"გასასვლელად გადაფურცლეთ ეკრანის ქვედა კიდიდან ზემოთ ან შეეხეთ ნებისმიერ ადგილას აპის ზემოთ"</string> </resources> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 94c8ea33a461..08b1f6262f1f 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -502,8 +502,8 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Battery saver қосулы"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Өнімділікті және фондық деректерді азайтады"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Battery saver функциясын өшіру"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілетін немесе жазу не трансляциялау кезінде құрылғыда ойнатылған барлық ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және ойнатылатын аудио сияқты ақпарат кіреді."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Осы функцияны ұсынатын қызмет экранда көрсетілетін немесе жазу не трансляциялау кезінде құрылғыда ойнатылған барлық ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және ойнатылатын аудио сияқты ақпарат кіреді."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> жазу не трансляциялау кезінде экранда көрсетілетін немесе дыбысталатын барлық ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және аудиоматериалдар кіреді."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Осы функцияны ұсынатын қызмет жазу не трансляциялау кезінде экранда көрсетілетін немесе құрылғыда дыбысталатын ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және аудиоматериалдар кіреді."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жазу немесе трансляциялау басталсын ба?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> арқылы жазу немесе трансляциялау басталсын ба?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Қайта көрсетпеу"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Жаңа басқару элементтерін көру үшін \"Қуат\" түймесін басып тұрыңыз."</string> <string name="controls_menu_add" msgid="4447246119229920050">"Басқару элементтерін енгізу"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Басқару элементтерін өзгерту"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Бір қолмен енгізу режимін пайдалану"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Шығу үшін экранның төменгі жағынан жоғары қарай сипаңыз немесе қолданбаның үстінен кез келген жерден түртіңіз."</string> </resources> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 5ba460adebf3..6d80ee47413c 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -502,10 +502,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"កម្មវិធីសន្សំថ្មបានបើក"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"ការបន្ថយការប្រតិបត្តិ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"បិទកម្មវិធីសន្សំថ្ម"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬបញ្ជូន។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែលផ្ដល់មុខងារនេះនឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬបញ្ជូន។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែលផ្ដល់មុខងារនេះនឹងមានសិទ្ធិចូលប្រើព័ត៌មានទាំងអស់ដែលអាចមើលឃើញនៅលើអេក្រង់របស់អ្នក ឬដែលចាក់ពីឧបករណ៍របស់អ្នក នៅពេលកំពុងថត ឬភ្ជាប់។ ព័ត៌មាននេះមានដូចជា ពាក្យសម្ងាត់ ព័ត៌មានលម្អិតអំពីការទូទាត់ប្រាក់ រូបថត សារ និងសំឡេងដែលអ្នកចាក់ជាដើម។"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើមថត ឬបញ្ជូនមែនទេ?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"ចាប់ផ្ដើមថត ឬបញ្ជូនដោយប្រើ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"ចាប់ផ្ដើមថត ឬភ្ជាប់ដោយប្រើ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"កុំបង្ហាញម្ដងទៀត"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាតទាំងអស់"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"សង្កត់ប៊ូតុងថាមពល ដើម្បីមើលឃើញការគ្រប់គ្រងថ្មីៗ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"បញ្ចូលផ្ទាំងគ្រប់គ្រង"</string> <string name="controls_menu_edit" msgid="890623986951347062">"កែផ្ទាំងគ្រប់គ្រង"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"កំពុងប្រើមុខងារប្រើដៃម្ខាង"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ដើម្បីចាកចេញ សូមអូសឡើងលើពីផ្នែកខាងក្រោមអេក្រង់ ឬចុចផ្នែកណាមួយនៅខាងលើកម្មវិធី"</string> </resources> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 7b8ed88bfd19..db2086458286 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -502,10 +502,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆನ್ ಆಗಿದೆ"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ಬ್ಯಾಟರಿ ಸೇವರ್ ಆಫ್ ಮಾಡಿ"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುವ ಅಥವಾ ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವಾಗ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲಾ ಮಾಹಿತಿಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುತ್ತವೆ. ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೊ ಪ್ಲೇಬ್ಯಾಕ್ನಂತಹ ಮಾಹಿತಿಯನ್ನು ಇದು ಒಳಗೊಂಡಿದೆ."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"ರೆಕಾರ್ಡ್ ಮಾಡುವಾಗ ಅಥವಾ ಬಿತ್ತರಿಸುವಾಗ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಕಾಣಿಸುವ ಸಕಲ ಮಾಹಿತಿಗೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಪ್ರವೇಶ ಹೊಂದಿರುತ್ತದೆ. ಇದು ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೊ ಪ್ಲೇಬ್ಯಾಕ್ನಂತಹ ಮಾಹಿತಿಯನ್ನು ಕೂಡ ಒಳಗೊಂಡಿರುತ್ತದೆ."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ಈ ವೈಶಿಷ್ಟ್ಯವು ಒದಗಿಸುವ ಸೇವೆಗಳು, ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುವ ಅಥವಾ ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವಾಗ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲಾ ಮಾಹಿತಿಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುತ್ತವೆ. ಪಾಸ್ವರ್ಡ್ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೊ ಪ್ಲೇಬ್ಯಾಕ್ನಂತಹ ಮಾಹಿತಿಯನ್ನು ಇದು ಒಳಗೊಂಡಿದೆ."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವಿಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಬೇಕೆ?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಬಳಸಿಕೊಂಡು ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸುವುದೇ?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಮೂಲಕ ರೆಕಾರ್ಡಿಂಗ್, ಬಿತ್ತರಿಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸುವುದೇ?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರು"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ಹೊಸ ನಿಯಂತ್ರಣಗಳನ್ನು ನೋಡಲು ಪವರ್ ಬಟನ್ ಹಿಡಿದುಕೊಳ್ಳಿ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ನಿಯಂತ್ರಣಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ಒಂದು ಕೈ ಮೋಡ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತಿದೆ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ನಿರ್ಗಮಿಸಲು, ಸ್ಕ್ರೀನ್ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ ಅಥವಾ ಆ್ಯಪ್ನ ಮೇಲೆ ಎಲ್ಲಿಯಾದರೂ ಟ್ಯಾಪ್ ಮಾಡಿ"</string> </resources> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 8d1177bec0ea..b43eb410c46d 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"새 컨트롤을 보려면 전원 버튼을 길게 누르세요."</string> <string name="controls_menu_add" msgid="4447246119229920050">"컨트롤 추가"</string> <string name="controls_menu_edit" msgid="890623986951347062">"컨트롤 수정"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"한 손 사용 모드 사용하기"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"화면 하단에서 위로 스와이프하거나 앱 상단을 탭하여 종료합니다."</string> </resources> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 794de98420d1..02e468a4f311 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -502,10 +502,10 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Батареяны үнөмдөгүч режими күйүк"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Иштин майнаптуулугун начарлатып, фондук дайын-даректерди чектейт"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Батареяны үнөмдөгүчтү өчүрүү"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"Бул функцияны аткарган <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> кызматы экраныңызда көрүнүп турган бардык маалыматты же жаздыруу жана тышкы экранга чыгаруу учурунда түзмөгүңүздө ойнотулган маалыматты колдоно алат. Буга сырсөздөр, төлөмдүн чоо-жайы, сүрөттөр, билдирүүлөр жана ойнотулган аудио кирет."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Бул функцияны аткарган кызматка экраныңыздагы бардык маалымат же түзмөктө ойнотулуп жаткан нерсе, сырсөздөр, төлөмдөрдүн чоо-жайы, сүрөттөр, билдирүүлөр жана аудио файлдар жеткиликтүү болот."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"Жаздырып же тышкы экранга чыгарып жатканда, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу экраныңыздагы бардык маалыматты же түзмөктө ойнолуп жаткан бардык нерселерди (сырсөздөрдү, төлөмдүн чоо-жайын, сүрөттөрдү, билдирүүлөрдү жана угуп жаткан аудиофайлдарды) көрө алат."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Жаздырып же тышкы экранга чыгарып жатканда, бул колдонмо экраныңыздагы бардык маалыматты же түзмөктө ойнолуп жаткан бардык нерселерди (сырсөздөрдү, төлөмдүн чоо-жайын, сүрөттөрдү, билдирүүлөрдү жана угуп жаткан аудиофайлдарды) көрө алат."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырып же тышкы экранга чыгарып баштайсызбы?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> менен жаздырылып же тышкы экранга чыгарылып башталсынбы?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу аркылуу жаздырып же тышкы экранга чыгарып баштайсызбы?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Экинчи көрүнбөсүн"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Башкаруу элементтерин көрүү үчүн күйгүзүү/өчүрүү баскычын коё бербей басып туруңуз"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Башкаруу элементтерин кошуу"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Башкаруу элементтерин түзөтүү"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Бир кол режимин колдонуу"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Чыгуу үчүн экранды ылдый жагынан өйдө көздөй сүрүңүз же колдонмонун өйдө жагын басыңыз"</string> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 2fe3f8075dbb..030bdc1ae120 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ກົດປຸ່ມເປີດປິດຄ້າງໄວ້ເພື່ອເບິ່ງການຄວບຄຸມໃໝ່"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ເພີ່ມການຄວບຄຸມ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ແກ້ໄຂການຄວບຄຸມ"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ກຳລັງໃຊ້ໂໝດມືດຽວ"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ເພື່ອອອກ, ໃຫ້ປັດຂຶ້ນຈາກລຸ່ມສຸດຂອງໜ້າຈໍ ຫຼື ແຕະບ່ອນໃດກໍໄດ້ຢູ່ເທິງແອັບ"</string> </resources> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 4489b7dd62ee..6f487416b322 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -508,7 +508,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Akumuliatoriaus tausojimo priemonė įjungta"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Sumažinamas našumas ir foninių duomenų naudojimas"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Išjungti Akumuliatoriaus tausojimo priemonę"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Šią funkcija teikianti paslauga galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Pradėti įrašyti ar perduoti turinį?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pradėti įrašyti ar perduoti turinį naudojant „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“?"</string> @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Jei norite peržiūrėti naujus valdiklius, laikykite paspaudę maitinimo mygtuką"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Pridėti valdiklių"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Redaguoti valdiklius"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Vienos rankos režimo naudojimas"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Jei norite išeiti, perbraukite aukštyn nuo ekrano apačios arba palieskite bet kur virš programos"</string> </resources> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index d4826e42f17c..bdea26a1a202 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Nospiediet barošanas pogu un turiet to, lai skatītu jaunas vadīklas"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Pievienot vadīklas"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Rediģēt vadīklas"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Vienas rokas režīma izmantošana"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Lai izietu, velciet augšup no ekrāna apakšdaļas vai pieskarieties jebkurā vietā virs lietotnes"</string> </resources> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 4836ecf1574a..c9f3777c6192 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -502,8 +502,8 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Штедачот на батерија е вклучен"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Ја намалува изведбата и податоците во заднина"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Исклучете го штедачот на батерија"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе има пристап до сите информации што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како, на пример, лозинки, детали на исплатата, фотографии, пораки и аудио што го пуштате."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите информации што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како, на пример, лозинки, детали на исплатата, фотографии, пораки и аудио што го пуштате."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува податоци како лозинки, детали за плаќање, фотографии, пораки, аудио што го пуштате итн."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува информации како лозинки, детали за плаќање, фотографии, пораки, аудио што го пуштате итн."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да почне снимање или емитување?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Да почне снимање или емитување со <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Не покажувај повторно"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Задржете го копчето за вклучување за да ги видите новите контроли"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Додајте контроли"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Изменете ги контролите"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Користење на режимот со една рака"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"За да излезете, повлечете нагоре од дното на екранот или допрете каде било над апликацијата"</string> </resources> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 863ce1152752..c968c2827437 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"ബാറ്ററി ലാഭിക്കൽ ഓണാണ്"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുക"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"റെക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്റ്റ് ചെയ്യുമ്പോഴോ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്ന് പ്ലേ ചെയ്യുന്നതോ നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ആയ എല്ലാ വിവരങ്ങളിലേക്കും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> എന്നതിന് ആക്സസ് ഉണ്ടായിരിക്കും. നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഒഡിയോ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, പാസ്വേഡുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഇതിൽ ഉൾപ്പെടുന്നു."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"റെക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്റ്റ് ചെയ്യുമ്പോഴോ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്ന് പ്ലേ ചെയ്യുന്നതോ നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ആയ എല്ലാ വിവരങ്ങളിലേക്കും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ന് ആക്സസ് ഉണ്ടായിരിക്കും. നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഒഡിയോ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, പാസ്വേഡുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഇതിൽ ഉൾപ്പെടുന്നു."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"റെക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്റ്റ് ചെയ്യുമ്പോഴോ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്ന് പ്ലേ ചെയ്യുന്നതോ നിങ്ങളുടെ സ്ക്രീനിൽ ദൃശ്യമാകുന്നതോ ആയ എല്ലാ വിവരങ്ങളിലേക്കും ഈ ഫംഗ്ഷൻ ലഭ്യമാക്കുന്ന സേവനത്തിന് ആക്സസ് ഉണ്ടായിരിക്കും. നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഓഡിയോ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, പേയ്മെന്റ് വിശദാംശങ്ങൾ, പാസ്വേഡുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഇതിൽ ഉൾപ്പെടുന്നു."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"റെക്കോർഡ് ചെയ്യൽ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യൽ ആരംഭിക്കണോ?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ഉപയോഗിച്ച് റെക്കോർഡ് ചെയ്യൽ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യൽ ആരംഭിക്കണോ?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"പുതിയ നിയന്ത്രണങ്ങൾ കാണാൻ പവർ ബട്ടൺ പിടിക്കുക"</string> <string name="controls_menu_add" msgid="4447246119229920050">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string> <string name="controls_menu_edit" msgid="890623986951347062">"നിയന്ത്രണങ്ങൾ എഡിറ്റ് ചെയ്യുക"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ഒറ്റക്കൈ മോഡ് എങ്ങനെ ഉപയോഗിക്കാം"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"പുറത്ത് കടക്കാൻ, സ്ക്രീനിന്റെ ചുവടെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക അല്ലെങ്കിൽ ആപ്പിന് മുകളിലായി എവിടെയെങ്കിലും ടാപ്പ് ചെയ്യുക"</string> </resources> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 107c3101a221..9ce6779e9ae4 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Шинэ хяналтыг харахын тулд асаах товчийг удаан дарна уу"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Хяналт нэмэх"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Хяналтыг өөрчлөх"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Нэг гарын горимыг ашиглаж байна"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шудрах эсвэл аппын дээд хэсэгт хүссэн газраа товшино уу"</string> </resources> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index bd2c3a5d09e9..d7126795089f 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -504,8 +504,8 @@ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"बॅटरी सेव्हर बंद करा"</string> <string name="media_projection_dialog_text" msgid="1755705274910034772">"तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अॅक्सेस <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ला असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"हे कार्य पुरवठा करणाऱ्या सेवेस तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अॅक्सेस असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string> - <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकॉर्ड किंवा कास्ट करणे सुरू करायचे आहे का ?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ने रेकॉर्ड करणे किंवा कास्ट करणे सुरू करा?"</string> + <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का ?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ने रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"पुन्हा दर्शवू नका"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"नवीन नियंत्रणे पाहण्यासाठी पॉवर बटण धरून ठेवा"</string> <string name="controls_menu_add" msgid="4447246119229920050">"नियंत्रणे जोडा"</string> <string name="controls_menu_edit" msgid="890623986951347062">"नियंत्रणे व्यवस्थापित करा"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"एकहाती मोड वापरणे"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"बाहेर पडण्यासाठी स्क्रीनच्या खालून वरच्या दिशेने स्वाइप करा किंवा ॲप आयकनच्या वर कोठेही टॅप करा"</string> </resources> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 029571b656ea..01e918ade0ee 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Tahan butang Kuasa untuk melihat kawalan baharu"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Tambah kawalan"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edit kawalan"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Menggunakan mod sebelah tangan"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Untuk keluar, leret ke atas daripada bahagian bawah skrin atau ketik pada mana-mana di bahagian atas apl"</string> </resources> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 6e632af3c5f4..23b0a06cca8f 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -502,8 +502,8 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"ဘက်ထရီ အားထိန်းကို ဖွင့်ထားခြင်း"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"ဘက်ထရီ အားထိန်းကို ပိတ်ရန်"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤလုပ်ရပ်အတွက် ဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်မျက်နှာပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> သည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤလုပ်ရပ်အတွက် ဝန်ဆောင်မှုသည် အသံဖမ်းနေစဉ် (သို့) ကာစ်လုပ်နေစဉ် သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်မှန်သမျှကို သုံးနိုင်ပြီး သင့်စက်မှ ဖွင့်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"နောက်ထပ် မပြပါနှင့်"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ထိန်းချုပ်မှုအသစ်များ ကြည့်ရန် ဖွင့်ပိတ်ခလုတ်ကို ဖိထားပါ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ထိန်းချုပ်မှုများ ထည့်ရန်"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ထိန်းချုပ်မှုများ တည်းဖြတ်ရန်"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"လက်တစ်ဖက်သုံးမုဒ် အသုံးပြုခြင်း"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"ထွက်ရန် ဖန်သားပြင်၏အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ သို့မဟုတ် အက်ပ်အပေါ်ဘက် မည်သည့်နေရာတွင်မဆို တို့ပါ"</string> </resources> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 5e29ca48bf7b..b0a593fe42f9 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Hold inne av/på-knappen for å se kontroller"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Legg til kontroller"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Endre kontroller"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bruk av enhåndsmodus"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"For å avslutte, sveip opp fra bunnen av skjermen eller trykk hvor som helst over appen"</string> </resources> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 098e0b1911d1..09462cf3ffcb 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"नयाँ नियन्त्रण सुविधाहरू हेर्न पावर बटन थिचिराख्नुहोस्"</string> <string name="controls_menu_add" msgid="4447246119229920050">"नियन्त्रण सुविधाहरू थप्नुहोस्"</string> <string name="controls_menu_edit" msgid="890623986951347062">"नियन्त्रण सुविधाहरू सम्पादन गर्नु…"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index e5012182eadc..2385017a0df7 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Houd de aan/uit-knop ingedrukt om nieuwe bedieningselementen te bekijken"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Bedieningselementen toevoegen"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Bedieningselementen bewerken"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Bediening met één hand gebruiken"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Als je wilt afsluiten, swipe je omhoog vanaf de onderkant van het scherm of tik je ergens boven de app"</string> </resources> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index bfd4bd77df31..d5c077b3ec1b 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ନୂଆ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ପାୱାର ବଟନକୁ ଧରି ରଖନ୍ତୁ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ସମ୍ପାଦନ କରନ୍ତୁ"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 1df919286a95..11567821397a 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1084,4 +1084,8 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"ਨਵੇਂ ਕੰਟਰੋਲ ਦੇਖਣ ਲਈ ਪਾਵਰ ਬਟਨ ਦਬਾਈ ਰੱਖੋ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="controls_menu_edit" msgid="890623986951347062">"ਕੰਟਰੋਲਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string> + <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> + <skip /> + <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> + <skip /> </resources> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 56fcbb20f5b5..1f6effe431e7 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Przytrzymaj przycisk zasilania, by zobaczyć nowe elementy sterujące"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj elementy sterujące"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Edytuj elementy sterujące"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Korzystanie z trybu jednej ręki"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Aby zamknąć, przesuń palcem z dołu ekranu w górę lub kliknij dowolne miejsce nad aplikacją"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 88f603200dc5..14d7a84dab28 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Economia de bateria ativada"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduz o desempenho e os dados em segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e o áudio que você tocar."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha o botão liga/desliga pressionado para ver os novos controles"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como usar o modo para uma mão"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string> </resources> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 5fdb2853551d..a6f7f004f411 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha premido o botão ligar/desligar para ver os novos controlos."</string> <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controlos"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controlos"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Utilizar o modo para uma mão"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize rapidamente para cima a partir da parte inferior do ecrã ou toque em qualquer ponto acima da app."</string> </resources> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 88f603200dc5..14d7a84dab28 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Economia de bateria ativada"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Reduz o desempenho e os dados em segundo plano"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Desativar a Economia de bateria"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e áudio que você toca."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"O app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> terá acesso a todas as informações visíveis na tela ou tocadas no dispositivo, como gravação ou transmissão. Isso inclui informações como senhas, detalhes de pagamento, fotos, mensagens e o áudio que você tocar."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mantenha o botão liga/desliga pressionado para ver os novos controles"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Adicionar controles"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editar controles"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Como usar o modo para uma mão"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para sair, deslize de baixo para cima na tela ou toque em qualquer lugar acima do app"</string> </resources> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index d5eecc76144c..0f15cfcd23f6 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Apăsați butonul de alimentare pentru a vedea noile comenzi"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Adăugați comenzi"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Editați comenzile"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Folosirea modului cu o mână"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Pentru a ieși, glisați în sus din partea de jos a ecranului sau atingeți oriunde deasupra ferestrei aplicației"</string> </resources> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 50850225c891..6196f88a7bfb 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Удерживайте кнопку питания, чтобы увидеть новые элементы управления"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Добавить виджеты"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Изменить виджеты"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Использование режима управления одной рукой"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Чтобы выйти, проведите по экрану снизу вверх или нажмите в любой области над значком приложения."</string> </resources> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index ff7e816f8336..8aca9f4e0dbd 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"නව පාලන බැලීමට බල බොත්තම අල්ලාගෙන සිටින්න"</string> <string name="controls_menu_add" msgid="4447246119229920050">"පාලන එක් කරන්න"</string> <string name="controls_menu_edit" msgid="890623986951347062">"පාලන සංස්කරණය කරන්න"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"තනි-අත් ප්රකාරය භාවිත කරමින්"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"පිටවීමට, තිරයේ පහළ සිට ඉහළට ස්වයිප් කරන්න හෝ යෙදුමට ඉහළින් ඕනෑම තැනක තට්ටු කරන්න"</string> </resources> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index a86da967ab62..45ee562b374c 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Pridržaním vypínača zobrazíte nové ovládacie prvky"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Pridať ovládače"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Upraviť ovládače"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Používanie režimu jednej ruky"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ukončíte potiahnutím z dolnej časti obrazovky nahor alebo klepnutím kdekoľvek nad aplikáciu"</string> </resources> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index b9039d8c3cb9..c7ad8ab92da3 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Za ogled novih kontrolnikov pridržite gumb za vklop"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Dodaj kontrolnike"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Uredi kontrolnike"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Uporaba enoročnega načina"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Za izhod povlecite z dna zaslona navzgor ali se dotaknite na poljubnem mestu nad aplikacijo"</string> </resources> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 2972c5383bee..3e0aecc16d4e 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -502,8 +502,8 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"\"Kursyesi i baterisë\" është i aktivizuar"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Pakëson veprimtarinë dhe të dhënat në sfond"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Çaktivizo \"Kursyesin e baterisë\""</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione si p.sh. fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Shërbimi që e ofron këtë funksion do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione si p.sh. fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione, si p.sh.: fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Shërbimi që e ofron këtë funksion do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione, si p.sh.: fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Do të fillosh regjistrimin ose transmetimin?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Fillo regjistrimin ose transmetimin me <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Mos e shfaq sërish"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Mbaj shtypur butonin e energjisë për të parë kontrollet e reja"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Shto kontrollet"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Modifiko kontrollet"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Po përdor modalitetin e përdorimit me një dorë"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Për të dalë, rrëshqit lart nga fundi i ekranit ose trokit diku mbi aplikacion"</string> </resources> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 77cbb96b3691..985041b3b24d 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1090,4 +1090,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Задржите дугме за укључивање да бисте видели нове контроле"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Додај контроле"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Измени контроле"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Коришћење режима једном руком"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Да бисте изашли, превуците нагоре од дна екрана или додирните било где изнад апликације"</string> </resources> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index c7eda4567a68..2018a383b5ed 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"De nya snabbkontrollerna visas om du håller strömbrytaren nedtryckt"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Lägg till snabbkontroller"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Redigera snabbkontroller"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Använda enhandsläge"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Avsluta genom att svepa uppåt från skärmens nederkant eller trycka ovanför appen"</string> </resources> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 2804f2f1e106..6eecc0e402fa 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Shikilia kitufe cha kuwasha/kuzima ili uone vidhibiti vipya"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Weka vidhibiti"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Badilisha vidhibiti"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Kutumia hali ya kutumia kwa mkono mmoja"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ili ufunge, telezesha kidole juu kutoka sehemu ya chini ya skrini au uguse mahali popote juu ya programu"</string> </resources> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index ee176fa3c57d..a05e0e735620 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"புதிய கட்டுப்பாடுகளைப் பார்க்க பவர் பட்டனைப் பிடித்திருக்கவும்"</string> <string name="controls_menu_add" msgid="4447246119229920050">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string> <string name="controls_menu_edit" msgid="890623986951347062">"கட்டுப்பாடுகளை மாற்றுதல்"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ஒற்றைக் கைப் பயன்முறையைப் பயன்படுத்துதல்"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"வெளியேற, திரையின் கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்யவும் அல்லது ஆப்ஸுக்கு மேலே எங்காவது தட்டவும்"</string> </resources> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index dc5ea1f29fb5..7d76abd0f20f 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"కొత్త నియంత్రణలను చూడడానికి పవర్ బటన్ని నొక్కి పట్టుకోండి"</string> <string name="controls_menu_add" msgid="4447246119229920050">"నియంత్రణలను జోడించండి"</string> <string name="controls_menu_edit" msgid="890623986951347062">"నియంత్రణలను ఎడిట్ చేయండి"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"వన్-హ్యాండెడ్ మోడ్ను ఉపయోగించడం"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"నిష్క్రమించడానికి, స్క్రీన్ కింది భాగం నుండి పైకి స్వైప్ చేయండి లేదా యాప్ పైన ఎక్కడైనా ట్యాప్ చేయండి"</string> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index ba9fd296f607..765c22424e89 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"กดปุ่มเปิด/ปิดค้างไว้เพื่อดูตัวควบคุมใหม่ๆ"</string> <string name="controls_menu_add" msgid="4447246119229920050">"เพิ่มตัวควบคุม"</string> <string name="controls_menu_edit" msgid="890623986951347062">"แก้ไขตัวควบคุม"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"การใช้โหมดมือเดียว"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"หากต้องการออก ให้เลื่อนขึ้นจากด้านล่างของหน้าจอหรือแตะที่ใดก็ได้เหนือแอป"</string> </resources> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 069438f2caed..c2cae9024a60 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Pindutin nang matagal ang Power button para makita ang mga bagong kontrol"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Magdagdag ng mga kontrol"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Mag-edit ng mga kontrol"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Gamit ang one-hand mode"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Para lumabas, mag-swipe pataas mula sa ibaba ng screen o mag-tap kahit saan sa itaas ng app"</string> </resources> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 649b9af53ff6..74b44f2079c6 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Yeni kontrolleri görmek için Güç düğmesini basılı tutun"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Denetim ekle"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Denetimleri düzenle"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Tek el modunu kullanma"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Çıkmak için ekranın alt kısmından yukarı kaydırın veya uygulamanın üzerinde herhangi bir yere dokunun"</string> </resources> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 6cb3ac8ce915..38c331ade344 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1096,4 +1096,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Утримуйте кнопку живлення, щоб переглянути нові елементи керування"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Додати елементи керування"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Змінити елементи керування"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Як користуватись режимом керування однією рукою"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Щоб вийти, проведіть пальцем вверх від низу екрана або торкніться екрана над додатком"</string> </resources> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 804c33436ea6..69ddabbe94ac 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"نئے کنٹرولز دیکھنے کے لیے پاور بٹن کو دبائے رکھیں"</string> <string name="controls_menu_add" msgid="4447246119229920050">"کنٹرولز شامل کریں"</string> <string name="controls_menu_edit" msgid="890623986951347062">"کنٹرولز میں ترمیم کریں"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"ایک ہاتھ کی وضع کا استعمال کرنا"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"باہر نکلنے کے لئے، اسکرین کے نیچے سے اوپر کی طرف سوائپ کریں یا ایپ کے اوپر کہیں بھی تھپتھپائیں"</string> </resources> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 6193d33961e6..ed704b0f5597 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -505,7 +505,7 @@ <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ekranda chiqqan yoki yozib olish va translatsiya vaqtida ijro etilgan barcha axborotlarga ruxsat oladi. Bu axborotlar parollar, toʻlov tafsilotlari, rasmlar, xabarlar va ijro etilgan audiolardan iborat boʻlishi mumkin."</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Bu funksiyani taʼminlovchi xizmat ekranda chiqqan yoki yozib olish va translatsiya vaqtida ijro etilgan barcha axborotlarga ruxsat oladi. Bu axborotlar parollar, toʻlov tafsilotlari, rasmlar, xabarlar va ijro etilgan audiolardan iborat boʻlishi mumkin."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Yozib olish yoki translatsiya boshlansinmi?"</string> - <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bilan yozib olinsin yoki translatsiya qilinsinmi?"</string> + <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> orqali yozib olish yoki translatsiya boshlansinmi?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Boshqa ko‘rsatilmasin"</string> <string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string> <string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Yangi boshqaruv elementlari bilan tanishish uchun quvvat tugmasini bosib turing"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Element kiritish"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Elementlarni tahrirlash"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ixcham rejimdan foydalaning"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Chiqish uchun ekran pastidan tepaga suring yoki ilovaning tepasidagi istalgan joyga bosing."</string> </resources> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 97ffbc623e02..5cc209941771 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -502,8 +502,8 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Trình tiết kiệm pin đang bật"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"Giảm hiệu suất và dữ liệu nền"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Tắt trình tiết kiệm pin"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào tất cả các thông tin hiển thị trên màn hình của bạn hoặc phát từ thiết bị trong khi ghi âm/ghi hình hoặc truyền, bao gồm cả thông tin như mật khẩu, chi tiết thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string> - <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Dịch vụ cung cấp chức năng này có quyền truy cập vào tất cả các thông tin hiển thị trên màn hình của bạn hoặc phát từ thiết bị trong khi ghi âm/ghi hình hoặc truyền, bao gồm cả thông tin như mật khẩu, chi tiết thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào tất cả các thông tin hiển thị trên màn hình của bạn hoặc phát trên thiết bị của bạn trong khi ghi âm/ghi hình hoặc truyền, bao gồm cả thông tin như mật khẩu, chi tiết thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string> + <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Dịch vụ cung cấp chức năng này có quyền truy cập vào tất cả các thông tin hiển thị trên màn hình của bạn hoặc phát trên thiết bị của bạn trong khi ghi âm/ghi hình hoặc truyền, bao gồm cả thông tin như mật khẩu, chi tiết thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Bắt đầu ghi âm/ghi hình hoặc truyền?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"Bắt đầu ghi âm/ghi hình hoặc truyền bằng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string> <string name="media_projection_remember_text" msgid="6896767327140422951">"Không hiển thị lại"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Giữ nút Nguồn để xem các tùy chọn điều khiển mới"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Thêm các tùy chọn điều khiển"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Chỉnh sửa tùy chọn điều khiển"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Cách dùng chế độ một tay"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Để thoát, hãy vuốt lên từ cuối màn hình hoặc nhấn vào vị trí bất kỳ phía trên ứng dụng"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index b9b146c9fb4b..f670bf682b64 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"按住电源按钮即可查看新控件"</string> <string name="controls_menu_add" msgid="4447246119229920050">"添加控件"</string> <string name="controls_menu_edit" msgid="890623986951347062">"修改控件"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用单手模式"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如需退出,请从屏幕底部向上滑动,或点按应用上方的任意位置"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index f2cb185078b5..2e26d6153a8f 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"按住「開關」按鈕以查看新控制項"</string> <string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string> <string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用單手模式"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如要退出,請從螢幕底部向上滑動,或輕按應用程式上方的任何位置"</string> </resources> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 69b52946d698..0049d2ec1f56 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -502,7 +502,7 @@ <string name="battery_saver_notification_title" msgid="8419266546034372562">"省電模式已開啟"</string> <string name="battery_saver_notification_text" msgid="2617841636449016951">"降低效能並限制背景數據傳輸"</string> <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"關閉省電模式"</string> - <string name="media_projection_dialog_text" msgid="1755705274910034772">"在錄製或投放內容時,「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string> + <string name="media_projection_dialog_text" msgid="1755705274910034772">"在錄製或投放內容時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string> <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在錄製或投放內容時,提供這項功能的服務可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string> <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要開始錄製或投放內容嗎?"</string> <string name="media_projection_dialog_title" msgid="3316063622495360646">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」開始錄製或投放內容嗎?"</string> @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"按住電源按鈕即可查看新的控制項"</string> <string name="controls_menu_add" msgid="4447246119229920050">"新增控制項"</string> <string name="controls_menu_edit" msgid="890623986951347062">"編輯控制項"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"使用單手模式"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"如要退出,請從螢幕底部向上滑動,或輕觸應用程式上方的任何位置"</string> </resources> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 5b899f93e5f9..c8c99b1c18c1 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1084,4 +1084,6 @@ <string name="controls_added_tooltip" msgid="4842812921719153085">"Bamba Inkinobho yamandla ukuze ubone izilawuli ezintsha"</string> <string name="controls_menu_add" msgid="4447246119229920050">"Engeza Izilawuli"</string> <string name="controls_menu_edit" msgid="890623986951347062">"Hlela izilawuli"</string> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Ukusebenzisa imodi yesandla esisodwa"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ukuze uphume, swayipha ngaphezulu kusuka ngezansi kwesikrini noma thepha noma kuphi ngenhla kohlelo lokusebenza"</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index d5f74a86fd94..816bcf8f274b 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -53,8 +53,8 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall ActivityInfo.CONFIG_DENSITY | ActivityInfo.CONFIG_ORIENTATION; @VisibleForTesting - protected WindowMagnificationAnimationController mWindowMagnificationAnimationController; - private final ModeSwitchesController mModeSwitchesController; + protected WindowMagnificationController mWindowMagnificationController; + protected final ModeSwitchesController mModeSwitchesController; private final Handler mHandler; private final AccessibilityManager mAccessibilityManager; private final CommandQueue mCommandQueue; @@ -72,11 +72,6 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall Context.ACCESSIBILITY_SERVICE); mCommandQueue = commandQueue; mModeSwitchesController = modeSwitchesController; - final WindowMagnificationController controller = new WindowMagnificationController(mContext, - mHandler, new SfVsyncFrameCallbackProvider(), null, - new SurfaceControl.Transaction(), this); - mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( - mContext, controller); } @Override @@ -86,7 +81,9 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall return; } mLastConfiguration.setTo(newConfig); - mWindowMagnificationAnimationController.onConfigurationChanged(configDiff); + if (mWindowMagnificationController != null) { + mWindowMagnificationController.onConfigurationChanged(configDiff); + } if (mModeSwitchesController != null) { mModeSwitchesController.onConfigurationChanged(configDiff); } @@ -100,25 +97,39 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall @MainThread void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) { //TODO: b/144080869 support multi-display. - mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY); + if (mWindowMagnificationController == null) { + mWindowMagnificationController = new WindowMagnificationController(mContext, + mHandler, + new SfVsyncFrameCallbackProvider(), + null, new SurfaceControl.Transaction(), + this); + } + mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY); } @MainThread void setScale(int displayId, float scale) { //TODO: b/144080869 support multi-display. - mWindowMagnificationAnimationController.setScale(scale); + if (mWindowMagnificationController != null) { + mWindowMagnificationController.setScale(scale); + } } @MainThread void moveWindowMagnifier(int displayId, float offsetX, float offsetY) { //TODO: b/144080869 support multi-display. - mWindowMagnificationAnimationController.moveWindowMagnifier(offsetX, offsetY); + if (mWindowMagnificationController != null) { + mWindowMagnificationController.moveWindowMagnifier(offsetX, offsetY); + } } @MainThread void disableWindowMagnification(int displayId) { //TODO: b/144080869 support multi-display. - mWindowMagnificationAnimationController.deleteWindowMagnification(); + if (mWindowMagnificationController != null) { + mWindowMagnificationController.deleteWindowMagnification(); + } + mWindowMagnificationController = null; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java deleted file mode 100644 index ae51623f3dc2..000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationAnimationController.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.accessibility; - -import android.animation.Animator; -import android.animation.ValueAnimator; -import android.annotation.IntDef; -import android.content.Context; -import android.content.res.Resources; -import android.util.Log; -import android.view.animation.AccelerateInterpolator; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.R; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Provides same functionality of {@link WindowMagnificationController}. Some methods run with - * the animation. - */ -class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUpdateListener, - Animator.AnimatorListener { - - private static final String TAG = "WindowMagnificationBridge"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - - @Retention(RetentionPolicy.SOURCE) - @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_DISABLING, STATE_ENABLING}) - @interface MagnificationState {} - - //The window magnification is disabled. - private static final int STATE_DISABLED = 0; - //The window magnification is enabled. - private static final int STATE_ENABLED = 1; - //The window magnification is going to be disabled when the animation is end. - private static final int STATE_DISABLING = 2; - //The animation is running for enabling the window magnification. - private static final int STATE_ENABLING = 3; - - private final WindowMagnificationController mController; - private final ValueAnimator mValueAnimator; - private final AnimationSpec mStartSpec = new AnimationSpec(); - private final AnimationSpec mEndSpec = new AnimationSpec(); - private final Context mContext; - - @MagnificationState - private int mState = STATE_DISABLED; - - WindowMagnificationAnimationController( - Context context, WindowMagnificationController controller) { - this(context, controller, newValueAnimator(context.getResources())); - } - - @VisibleForTesting - WindowMagnificationAnimationController(Context context, - WindowMagnificationController controller, ValueAnimator valueAnimator) { - mContext = context; - mController = controller; - mValueAnimator = valueAnimator; - mValueAnimator.addUpdateListener(this); - mValueAnimator.addListener(this); - } - - /** - * Wraps {@link WindowMagnificationController#enableWindowMagnification(float, float, float)} - * with transition animation. If the window magnification is not enabled, the scale will start - * from 1.0 and the center won't be changed during the animation. If {@link #mState} is - * {@code STATE_DISABLING}, the animation runs in reverse. - * - * @param scale the target scale, or {@link Float#NaN} to leave unchanged. - * @param centerX the screen-relative X coordinate around which to center, - * or {@link Float#NaN} to leave unchanged. - * @param centerY the screen-relative Y coordinate around which to center, - * or {@link Float#NaN} to leave unchanged. - * - * @see #onAnimationUpdate(ValueAnimator) - */ - void enableWindowMagnification(float scale, float centerX, float centerY) { - if (mState == STATE_ENABLING) { - mValueAnimator.cancel(); - } - setupEnableAnimationSpecs(scale, centerX, centerY); - - if (mEndSpec.equals(mStartSpec)) { - setState(STATE_ENABLED); - } else { - if (mState == STATE_DISABLING) { - mValueAnimator.reverse(); - } else { - mValueAnimator.start(); - } - setState(STATE_ENABLING); - } - } - - private void setupEnableAnimationSpecs(float scale, float centerX, float centerY) { - final float currentScale = mController.getScale(); - final float currentCenterX = mController.getCenterX(); - final float currentCenterY = mController.getCenterY(); - - if (mState == STATE_DISABLED) { - //We don't need to offset the center during the animation. - mStartSpec.set(/* scale*/ 1.0f, centerX, centerY); - mEndSpec.set(Float.isNaN(scale) ? mContext.getResources().getInteger( - R.integer.magnification_default_scale) : scale, centerX, centerY); - } else { - mStartSpec.set(currentScale, currentCenterX, currentCenterY); - mEndSpec.set(Float.isNaN(scale) ? currentScale : scale, - Float.isNaN(centerX) ? currentCenterX : centerX, - Float.isNaN(centerY) ? currentCenterY : centerY); - } - if (DEBUG) { - Log.d(TAG, "SetupEnableAnimationSpecs : mStartSpec = " + mStartSpec + ", endSpec = " - + mEndSpec); - } - } - - /** - * Wraps {@link WindowMagnificationController#setScale(float)}. If the animation is - * running, it has no effect. - */ - void setScale(float scale) { - if (mValueAnimator.isRunning()) { - return; - } - mController.setScale(scale); - } - - /** - * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition - * animation. If the window magnification is enabling, it runs the animation in reverse. - */ - void deleteWindowMagnification() { - if (mState == STATE_DISABLED || mState == STATE_DISABLING) { - return; - } - mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN); - mEndSpec.set(/* scale*/ mController.getScale(), Float.NaN, Float.NaN); - - mValueAnimator.reverse(); - setState(STATE_DISABLING); - } - - /** - * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the - * animation is running, it has no effect. - * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in - * current screen pixels. - * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in - * current screen pixels. - */ - void moveWindowMagnifier(float offsetX, float offsetY) { - if (mValueAnimator.isRunning()) { - return; - } - mController.moveWindowMagnifier(offsetX, offsetY); - } - - void onConfigurationChanged(int configDiff) { - mController.onConfigurationChanged(configDiff); - } - - private void setState(@MagnificationState int state) { - if (DEBUG) { - Log.d(TAG, "setState from " + mState + " to " + state); - } - mState = state; - } - - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - if (mState == STATE_DISABLING) { - mController.deleteWindowMagnification(); - setState(STATE_DISABLED); - } else if (mState == STATE_ENABLING) { - setState(STATE_ENABLED); - } else { - Log.w(TAG, "onAnimationEnd unexpected state:" + mState); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - final float fract = animation.getAnimatedFraction(); - final float sentScale = mStartSpec.mScale + (mEndSpec.mScale - mStartSpec.mScale) * fract; - final float centerX = - mStartSpec.mCenterX + (mEndSpec.mCenterX - mStartSpec.mCenterX) * fract; - final float centerY = - mStartSpec.mCenterY + (mEndSpec.mCenterY - mStartSpec.mCenterY) * fract; - mController.enableWindowMagnification(sentScale, centerX, centerY); - } - - private static ValueAnimator newValueAnimator(Resources resources) { - final ValueAnimator valueAnimator = new ValueAnimator(); - valueAnimator.setDuration( - resources.getInteger(com.android.internal.R.integer.config_longAnimTime)); - valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f)); - valueAnimator.setFloatValues(0.0f, 1.0f); - return valueAnimator; - } - - private static class AnimationSpec { - private float mScale = Float.NaN; - private float mCenterX = Float.NaN; - private float mCenterY = Float.NaN; - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other == null || getClass() != other.getClass()) { - return false; - } - - final AnimationSpec s = (AnimationSpec) other; - return mScale == s.mScale && mCenterX == s.mCenterX && mCenterY == s.mCenterY; - } - - @Override - public int hashCode() { - int result = (mScale != +0.0f ? Float.floatToIntBits(mScale) : 0); - result = 31 * result + (mCenterX != +0.0f ? Float.floatToIntBits(mCenterX) : 0); - result = 31 * result + (mCenterY != +0.0f ? Float.floatToIntBits(mCenterY) : 0); - return result; - } - - void set(float scale, float centerX, float centerY) { - mScale = scale; - mCenterX = centerX; - mCenterY = centerY; - } - - @Override - public String toString() { - return "AnimationSpec{" - + "mScale=" + mScale - + ", mCenterX=" + mCenterX - + ", mCenterY=" + mCenterY - + '}'; - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 6d3e8ba68395..798b751c03ee 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -150,7 +150,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mMirrorViewGeometryVsyncCallback = l -> { - if (isWindowVisible() && mMirrorSurface != null) { + if (mMirrorView != null && mMirrorSurface != null) { calculateSourceBounds(mMagnificationFrame, mScale); // The final destination for the magnification surface should be at 0,0 // since the ViewRootImpl's position will change @@ -502,7 +502,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold /** * Enables window magnification with specified parameters. * - * @param scale the target scale, or {@link Float#NaN} to leave unchanged + * @param scale the target scale * @param centerX the screen-relative X coordinate around which to center, * or {@link Float#NaN} to leave unchanged. * @param centerY the screen-relative Y coordinate around which to center, @@ -513,10 +513,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold : centerX - mMagnificationFrame.exactCenterX(); final float offsetY = Float.isNaN(centerY) ? 0 : centerY - mMagnificationFrame.exactCenterY(); - mScale = Float.isNaN(scale) ? mScale : scale; + mScale = scale; setMagnificationFrameBoundary(); updateMagnificationFramePosition((int) offsetX, (int) offsetY); - if (!isWindowVisible()) { + if (mMirrorView == null) { createMirrorWindow(); showControls(); } else { @@ -527,10 +527,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold /** * Sets the scale of the magnified region if it's visible. * - * @param scale the target scale, or {@link Float#NaN} to leave unchanged + * @param scale the target scale */ void setScale(float scale) { - if (!isWindowVisible() || mScale == scale) { + if (mMirrorView == null || mScale == scale) { return; } enableWindowMagnification(scale, Float.NaN, Float.NaN); @@ -552,35 +552,4 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold modifyWindowMagnification(mTransaction); } } - - /** - * Gets the scale. - * @return {@link Float#NaN} if the window is invisible. - */ - float getScale() { - return isWindowVisible() ? mScale : Float.NaN; - } - - /** - * Returns the screen-relative X coordinate of the center of the magnified bounds. - * - * @return the X coordinate. {@link Float#NaN} if the window is invisible. - */ - float getCenterX() { - return isWindowVisible() ? mMagnificationFrame.exactCenterX() : Float.NaN; - } - - /** - * Returns the screen-relative Y coordinate of the center of the magnified bounds. - * - * @return the Y coordinate. {@link Float#NaN} if the window is invisible. - */ - float getCenterY() { - return isWindowVisible() ? mMagnificationFrame.exactCenterY() : Float.NaN; - } - - //The window is visible when it is existed. - private boolean isWindowVisible() { - return mMirrorView != null; - } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index d0f61817d1cc..fa0d2ba84b4e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -310,7 +310,6 @@ public class BubbleExpandedView extends LinearLayout { // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); - mActivityViewContainer.setBackgroundColor(Color.WHITE); mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { @@ -439,9 +438,11 @@ public class BubbleExpandedView extends LinearLayout { } void applyThemeAttrs() { - final TypedArray ta = mContext.obtainStyledAttributes( - new int[] {android.R.attr.dialogCornerRadius}); + final TypedArray ta = mContext.obtainStyledAttributes(new int[] { + android.R.attr.dialogCornerRadius, + android.R.attr.colorBackgroundFloating}); mCornerRadius = ta.getDimensionPixelSize(0, 0); + mActivityViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE)); ta.recycle(); if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows( diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java index ded386159dca..563684ad65c1 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java @@ -159,7 +159,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, } else { float distance = (float) Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y); - if (distance > mDragDistThreshold && mPassedSlop) { + if (distance > mDragDistThreshold) { mGestureEventCallback.onStop(); } } @@ -273,13 +273,13 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback, */ public interface OneHandedGestureEventCallback { /** - * Handle the start event event, and return whether the event was consumed. + * Handles the start gesture. */ - boolean onStart(); + void onStart(); /** - * Handle the exit event event, and return whether the event was consumed. + * Handles the exit gesture. */ - boolean onStop(); + void onStop(); } } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java index 51e587586852..a3921ee54fec 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java @@ -24,6 +24,7 @@ import android.content.ComponentName; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; +import android.view.KeyEvent; import androidx.annotation.NonNull; @@ -33,6 +34,7 @@ import com.android.systemui.R; import com.android.systemui.model.SysUiState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; @@ -50,9 +52,11 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { private static final String TAG = "OneHandedManager"; private boolean mIsOneHandedEnabled; + private boolean mIsSwipeToNotificationEnabled; private boolean mTaskChangeToExit; private float mOffSetFraction; + private final CommandQueue mCommandQueue; private final DisplayController mDisplayController; private final OneHandedGestureHandler mGestureHandler; private final OneHandedTimeoutHandler mTimeoutHandler; @@ -60,11 +64,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { private final OneHandedTutorialHandler mTutorialHandler; private final SysUiState mSysUiFlagContainer; - private Context mContext; private OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer; - private OneHandedGestureHandler.OneHandedGestureEventCallback mGestureEventCallback; - private OneHandedTouchHandler.OneHandedTouchEventCallback mTouchEventCallback; - private OneHandedTransitionCallback mTransitionCallback; /** * Handler for system task stack changes, exit when user lunch new task or bring task to front @@ -105,13 +105,14 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { */ @Inject public OneHandedManagerImpl(Context context, + CommandQueue commandQueue, DisplayController displayController, OneHandedDisplayAreaOrganizer displayAreaOrganizer, OneHandedTouchHandler touchHandler, OneHandedTutorialHandler tutorialHandler, OneHandedGestureHandler gestureHandler, SysUiState sysUiState) { - mContext = context; + mCommandQueue = commandQueue; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; mDisplayController.addDisplayChangingController(mRotationController); @@ -120,6 +121,8 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { context.getResources().getFraction(R.fraction.config_one_handed_offset, 1, 1); mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( context.getContentResolver()); + mIsSwipeToNotificationEnabled = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + context.getContentResolver()); mTimeoutHandler = OneHandedTimeoutHandler.get(); mTouchHandler = touchHandler; mTutorialHandler = tutorialHandler; @@ -148,11 +151,19 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { } /** - * Start one handed mode + * Sets whether to enable swipe bottom to notification gesture when user update settings. + */ + public void setSwipeToNotificationEnabled(boolean enabled) { + mIsSwipeToNotificationEnabled = enabled; + updateOneHandedEnabled(); + } + + /** + * Enters one handed mode. */ @Override public void startOneHanded() { - if (!mDisplayAreaOrganizer.isInOneHanded() && mIsOneHandedEnabled) { + if (!mDisplayAreaOrganizer.isInOneHanded()) { final int yOffSet = Math.round(getDisplaySize().y * mOffSetFraction); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); @@ -160,7 +171,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { } /** - * Stop one handed mode + * Exits one handed mode. */ @Override public void stopOneHanded() { @@ -171,53 +182,45 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { } private void setupGestures() { - mTouchEventCallback = new OneHandedTouchHandler.OneHandedTouchEventCallback() { - @Override - public boolean onStart() { - boolean result = false; - if (!mDisplayAreaOrganizer.isInOneHanded()) { - startOneHanded(); - result = true; - } - return result; - } + mTouchHandler.registerTouchEventListener( + new OneHandedTouchHandler.OneHandedTouchEventCallback() { + @Override + public void onStart() { + if (mIsOneHandedEnabled) { + startOneHanded(); + } + } - @Override - public boolean onStop() { - boolean result = false; - if (mDisplayAreaOrganizer.isInOneHanded()) { - stopOneHanded(); - result = true; - } - return result; - } - }; - mTouchHandler.registerTouchEventListener(mTouchEventCallback); + @Override + public void onStop() { + if (mIsOneHandedEnabled) { + stopOneHanded(); + } + } + }); - mGestureEventCallback = new OneHandedGestureHandler.OneHandedGestureEventCallback() { - @Override - public boolean onStart() { - boolean result = false; - if (!mDisplayAreaOrganizer.isInOneHanded()) { - startOneHanded(); - result = true; - } - return result; - } + mGestureHandler.setGestureEventListener( + new OneHandedGestureHandler.OneHandedGestureEventCallback() { + @Override + public void onStart() { + if (mIsOneHandedEnabled) { + startOneHanded(); + } else if (mIsSwipeToNotificationEnabled) { + mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN); + } + } - @Override - public boolean onStop() { - boolean result = false; - if (mDisplayAreaOrganizer.isInOneHanded()) { - stopOneHanded(); - result = true; - } - return result; - } - }; - mGestureHandler.setGestureEventListener(mGestureEventCallback); + @Override + public void onStop() { + if (mIsOneHandedEnabled) { + stopOneHanded(); + } else if (mIsSwipeToNotificationEnabled) { + mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP); + } + } + }); - mTransitionCallback = new OneHandedTransitionCallback() { + mDisplayAreaOrganizer.registerTransitionCallback(new OneHandedTransitionCallback() { @Override public void onStartFinished(Rect bounds) { mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, @@ -229,8 +232,8 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { mSysUiFlagContainer.setFlag(SYSUI_STATE_ONE_HANDED_ACTIVE, false).commitUpdate(DEFAULT_DISPLAY); } - }; - mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallback); + }); + mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler); mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler); mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler); @@ -264,7 +267,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable { ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); } mTouchHandler.onOneHandedEnabled(mIsOneHandedEnabled); - mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled); + mGestureHandler.onOneHandedEnabled(mIsOneHandedEnabled || mIsSwipeToNotificationEnabled); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java index 9b232cd0a19d..1b6ec04193f0 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedSettingsUtil.java @@ -132,6 +132,14 @@ public final class OneHandedSettingsUtil { Settings.Secure.ONE_HANDED_MODE_TIMEOUT, ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); } + /** + * Returns whether swipe bottom to notification gesture enabled or not. + */ + public static boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver) { + return Settings.Secure.getInt(resolver, + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0) == 1; + } + protected static void dump(PrintWriter pw, String prefix, ContentResolver resolver) { final String innerPrefix = prefix + " "; pw.println(prefix + TAG); diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java index d616a3a45b90..1446e5a431c6 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java @@ -175,13 +175,13 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa */ public interface OneHandedTouchEventCallback { /** - * Handle the start event event, and return whether the event was consumed. + * Handle the start event. */ - boolean onStart(); + void onStart(); /** - * Handle the exit event event, and return whether the event was consumed. + * Handle the exit event. */ - boolean onStop(); + void onStop(); } } diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java index 9239435f1622..0903c0e5c512 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java @@ -40,7 +40,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.SystemUI; -import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.statusbar.CommandQueue; @@ -80,7 +79,10 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mOneHandedManager.setOneHandedEnabled(enabled); } - setEnabledGesturalOverlay(enabled); + // Also checks swipe to notification settings since they all need gesture overlay. + setEnabledGesturalOverlay( + enabled || OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + mContext.getContentResolver())); } }; @@ -130,11 +132,28 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum } }; + private final ContentObserver mSwipeToNotificationEnabledObserver = + new ContentObserver(mMainHandler) { + @Override + public void onChange(boolean selfChange) { + final boolean enabled = + OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + mContext.getContentResolver()); + if (mOneHandedManager != null) { + mOneHandedManager.setSwipeToNotificationEnabled(enabled); + } + + // Also checks one handed mode settings since they all need gesture overlay. + setEnabledGesturalOverlay( + enabled || OneHandedSettingsUtil.getSettingsOneHandedModeEnabled( + mContext.getContentResolver())); + } + }; + @Inject public OneHandedUI(Context context, CommandQueue commandQueue, OneHandedManagerImpl oneHandedManager, - DumpManager dumpManager, OneHandedSettingsUtil settingsUtil, ScreenLifecycle screenLifecycle) { super(context); @@ -239,6 +258,9 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mContext.getContentResolver(), mTimeoutObserver); mSettingUtil.registerSettingsKeyObserver(Settings.Secure.TAPS_APP_TO_EXIT, mContext.getContentResolver(), mTaskChangeExitObserver); + mSettingUtil.registerSettingsKeyObserver( + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, + mContext.getContentResolver(), mSwipeToNotificationEnabledObserver); } private void updateSettings() { @@ -248,6 +270,8 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum mSettingUtil.getSettingsOneHandedModeTimeout(mContext.getContentResolver())); mOneHandedManager.setTaskChangeToExit( mSettingUtil.getSettingsTapsAppToExit(mContext.getContentResolver())); + mOneHandedManager.setSwipeToNotificationEnabled( + mSettingUtil.getSettingsSwipeToNotificationEnabled(mContext.getContentResolver())); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index 3264429a1723..d8548decc5f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -67,7 +67,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private static final String PATTERN_HOUR_MINUTE = "h:mm a"; private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm"; - private final ColorDisplayManager mManager; + private ColorDisplayManager mManager; private final LocationController mLocationController; private final NightDisplayListenerModule.Builder mNightDisplayListenerBuilder; private NightDisplayListener mListener; @@ -126,6 +126,8 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements mListener.setCallback(null); } + mManager = getHost().getUserContext().getSystemService(ColorDisplayManager.class); + // Make a new controller for the new user. mListener = mNightDisplayListenerBuilder.setUser(newUserId).build(); if (mIsListening) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 07b841ffb6f7..78975a4798ce 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -58,10 +58,9 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a"); private final Icon mIcon = ResourceIcon.get( com.android.internal.R.drawable.ic_qs_ui_mode_night); - private final UiModeManager mUiModeManager; + private UiModeManager mUiModeManager; private final BatteryController mBatteryController; private final LocationController mLocationController; - @Inject public UiModeNightTile( QSHost host, @@ -78,7 +77,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; - mUiModeManager = mContext.getSystemService(UiModeManager.class); + mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class); mLocationController = locationController; configurationController.observe(getLifecycle(), this); batteryController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java index 71e788375d5e..1bea72aea2ba 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java @@ -385,7 +385,7 @@ public class BrightnessController implements ToggleSlider.Listener { if (stopTracking) { // TODO(brightnessfloat): change to use float value instead. MetricsLogger.action(mContext, metric, - BrightnessSynchronizer.brightnessFloatToInt(mContext, valFloat)); + BrightnessSynchronizer.brightnessFloatToInt(valFloat)); } setBrightness(valFloat); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java index 53b369c3543e..eb476457dcec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ContextualButton.java @@ -34,6 +34,7 @@ public class ContextualButton extends ButtonDispatcher { private ContextButtonListener mListener; private ContextualButtonGroup mGroup; + protected final Context mLightContext; protected final @DrawableRes int mIconResId; /** @@ -42,8 +43,10 @@ public class ContextualButton extends ButtonDispatcher { * @param buttonResId the button view from xml layout * @param iconResId icon resource to be used */ - public ContextualButton(@IdRes int buttonResId, @DrawableRes int iconResId) { + public ContextualButton(@IdRes int buttonResId, Context lightContext, + @DrawableRes int iconResId) { super(buttonResId); + mLightContext = lightContext; mIconResId = iconResId; } @@ -117,17 +120,8 @@ public class ContextualButton extends ButtonDispatcher { } protected KeyButtonDrawable getNewDrawable(int lightIconColor, int darkIconColor) { - return KeyButtonDrawable.create(getContext().getApplicationContext(), lightIconColor, - darkIconColor, mIconResId, false /* shadow */, null /* ovalBackground */); - } - - /** - * This context is from the view that could be stale after rotation or config change. To get - * correct resources use getApplicationContext() as well. - * @return current view context - */ - protected Context getContext() { - return getCurrentView().getContext(); + return KeyButtonDrawable.create(mLightContext, lightIconColor, darkIconColor, mIconResId, + false /* shadow */, null /* ovalBackground */); } public interface ContextButtonListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 6297052550c3..8c5e2ceaeadf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -375,6 +375,34 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; + private static class NavBarViewAttachedListener implements View.OnAttachStateChangeListener { + private NavigationBarFragment mFragment; + private FragmentListener mListener; + + NavBarViewAttachedListener(NavigationBarFragment fragment, FragmentListener listener) { + mFragment = fragment; + mListener = listener; + } + + @Override + public void onViewAttachedToWindow(View v) { + final FragmentHostManager fragmentHost = FragmentHostManager.get(v); + fragmentHost.getFragmentManager().beginTransaction() + .replace(R.id.navigation_bar_frame, mFragment, TAG) + .commit(); + fragmentHost.addTagListener(TAG, mListener); + mFragment = null; + } + + @Override + public void onViewDetachedFromWindow(View v) { + final FragmentHostManager fragmentHost = FragmentHostManager.get(v); + fragmentHost.removeTagListener(TAG, mListener); + FragmentHostManager.removeAndDestroy(v); + v.removeOnAttachStateChangeListener(this); + } + } + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -1470,26 +1498,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView); if (navigationBarView == null) return null; - navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - final NavigationBarFragment fragment = - FragmentHostManager.get(v).create(NavigationBarFragment.class); - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.getFragmentManager().beginTransaction() - .replace(R.id.navigation_bar_frame, fragment, TAG) - .commit(); - fragmentHost.addTagListener(TAG, listener); - } - - @Override - public void onViewDetachedFromWindow(View v) { - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.removeTagListener(TAG, listener); - FragmentHostManager.removeAndDestroy(v); - navigationBarView.removeOnAttachStateChangeListener(this); - } - }); + NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView) + .create(NavigationBarFragment.class); + navigationBarView.addOnAttachStateChangeListener(new NavBarViewAttachedListener(fragment, + listener)); context.getSystemService(WindowManager.class).addView(navigationBarView, lp); return navigationBarView; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 84512ac85fa9..0b4a2b69ffb3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -295,11 +295,12 @@ public class NavigationBarView extends FrameLayout implements // Set up the context group of buttons mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container); final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher, - R.drawable.ic_ime_switcher_default); + mLightContext, R.drawable.ic_ime_switcher_default); final RotationContextButton rotateSuggestionButton = new RotationContextButton( - R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button_ccw_start_0); + R.id.rotate_suggestion, mLightContext, + R.drawable.ic_sysbar_rotate_button_ccw_start_0); final ContextualButton accessibilityButton = - new ContextualButton(R.id.accessibility_button, + new ContextualButton(R.id.accessibility_button, mLightContext, R.drawable.ic_sysbar_accessibility_button); mContextualButtonGroup.addButton(imeSwitcherButton); if (!isGesturalMode) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java index f83cdd488c04..b0630a649ffe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java @@ -283,7 +283,6 @@ public class RotationButtonController { return; } - // TODO: Remove styles? // Prepare to show the navbar icon by updating the icon style to change anim params mLastRotationSuggestion = rotation; // Remember rotation for click final boolean rotationCCW = isRotationAnimationCCW(windowRotation, rotation); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java index d7e95e43ea8f..08aeb0425f68 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java @@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone; import android.annotation.DrawableRes; import android.annotation.IdRes; +import android.content.Context; import android.view.View; import com.android.systemui.statusbar.policy.KeyButtonDrawable; @@ -28,8 +29,12 @@ public class RotationContextButton extends ContextualButton implements RotationB private RotationButtonController mRotationButtonController; - public RotationContextButton(@IdRes int buttonResId, @DrawableRes int iconResId) { - super(buttonResId, iconResId); + /** + * @param lightContext the context to use to load the icon resource + */ + public RotationContextButton(@IdRes int buttonResId, Context lightContext, + @DrawableRes int iconResId) { + super(buttonResId, lightContext, iconResId); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java index b5f98ad47c09..89297fd83bb0 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java @@ -54,7 +54,7 @@ public class UsbAccessoryUriActivity extends AlertActivity String uriString = intent.getStringExtra("uri"); mUri = (uriString == null ? null : Uri.parse(uriString)); - // sanity check before displaying dialog + // Exception check before displaying dialog if (mUri == null) { Log.e(TAG, "could not parse Uri " + uriString); finish(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java index ac567e0ae67d..fbc8e9d8de79 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/IWindowMagnificationConnectionTest.java @@ -25,7 +25,6 @@ import android.content.Context; import android.os.RemoteException; import android.provider.Settings; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.view.Display; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IWindowMagnificationConnection; @@ -48,7 +47,6 @@ import org.mockito.MockitoAnnotations; */ @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper public class IWindowMagnificationConnectionTest extends SysuiTestCase { private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; @@ -59,7 +57,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { @Mock private IWindowMagnificationConnectionCallback mConnectionCallback; @Mock - private WindowMagnificationAnimationController mWindowMagnificationAnimationController; + private WindowMagnificationController mWindowMagnificationController; @Mock private ModeSwitchesController mModeSwitchesController; private IWindowMagnificationConnection mIWindowMagnificationConnection; @@ -76,8 +74,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { any(IWindowMagnificationConnection.class)); mWindowMagnification = new WindowMagnification(getContext(), getContext().getMainThreadHandler(), mCommandQueue, mModeSwitchesController); - mWindowMagnification.mWindowMagnificationAnimationController = - mWindowMagnificationAnimationController; + mWindowMagnification.mWindowMagnificationController = mWindowMagnificationController; mWindowMagnification.requestWindowMagnificationConnection(true); assertNotNull(mIWindowMagnificationConnection); mIWindowMagnificationConnection.setConnectionCallback(mConnectionCallback); @@ -89,7 +86,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { Float.NaN); waitForIdleSync(); - verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN, + verify(mWindowMagnificationController).enableWindowMagnification(3.0f, Float.NaN, Float.NaN); } @@ -102,7 +99,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY); waitForIdleSync(); - verify(mWindowMagnificationAnimationController).deleteWindowMagnification(); + verify(mWindowMagnificationController).deleteWindowMagnification(); } @Test @@ -110,7 +107,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.setScale(TEST_DISPLAY, 3.0f); waitForIdleSync(); - verify(mWindowMagnificationAnimationController).setScale(3.0f); + verify(mWindowMagnificationController).setScale(3.0f); } @Test @@ -118,7 +115,7 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase { mIWindowMagnificationConnection.moveWindowMagnifier(TEST_DISPLAY, 100f, 200f); waitForIdleSync(); - verify(mWindowMagnificationAnimationController).moveWindowMagnifier(100f, 200f); + verify(mWindowMagnificationController).moveWindowMagnifier(100f, 200f); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java deleted file mode 100644 index add0843c2994..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.accessibility; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import android.animation.ValueAnimator; -import android.app.Instrumentation; -import android.content.Context; -import android.os.Handler; -import android.os.SystemClock; -import android.testing.AndroidTestingRunner; -import android.view.SurfaceControl; -import android.view.animation.AccelerateInterpolator; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.MediumTest; - -import com.android.internal.graphics.SfVsyncFrameCallbackProvider; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.util.concurrent.atomic.AtomicReference; - - -@MediumTest -@RunWith(AndroidTestingRunner.class) -public class WindowMagnificationAnimationControllerTest extends SysuiTestCase { - - private static final float DEFAULT_SCALE = 3.0f; - private static final float DEFAULT_CENTER_X = 400.0f; - private static final float DEFAULT_CENTER_Y = 500.0f; - private static final long ANIMATION_DURATION_MS = 100; - - private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0); - private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0); - private AtomicReference<Float> mCurrentCenterY = new AtomicReference<>((float) 0); - private ArgumentCaptor<Float> mScaleCaptor = ArgumentCaptor.forClass(Float.class); - private ArgumentCaptor<Float> mCenterXCaptor = ArgumentCaptor.forClass(Float.class); - private ArgumentCaptor<Float> mCenterYCaptor = ArgumentCaptor.forClass(Float.class); - - @Mock - Handler mHandler; - @Mock - SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; - @Mock - WindowMagnifierCallback mWindowMagnifierCallback; - - private SpyWindowMagnificationController mController; - private WindowMagnificationController mSpyController; - private WindowMagnificationAnimationController mWindowMagnificationAnimationController; - private Instrumentation mInstrumentation; - private long mWaitingAnimationPeriod; - private long mWaitIntermediateAnimationPeriod; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mWaitingAnimationPeriod = ANIMATION_DURATION_MS + 50; - mWaitIntermediateAnimationPeriod = ANIMATION_DURATION_MS / 2; - mController = new SpyWindowMagnificationController(mContext, mHandler, - mSfVsyncFrameProvider, null, new SurfaceControl.Transaction(), - mWindowMagnifierCallback); - mSpyController = mController.getSpyController(); - mWindowMagnificationAnimationController = new WindowMagnificationAnimationController( - mContext, mController, newValueAnimator()); - } - - @Test - public void enableWindowMagnification_disabled_expectedStartAndEndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification( - mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - verifyStartValue(mScaleCaptor, 1.0f); - verifyStartValue(mCenterXCaptor, DEFAULT_CENTER_X); - verifyStartValue(mCenterYCaptor, DEFAULT_CENTER_Y); - verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); - } - - @Test - public void enableWindowMagnification_enabling_expectedStartAndEndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); - final float targetScale = DEFAULT_SCALE + 1.0f; - final float targetCenterX = DEFAULT_CENTER_X + 100; - final float targetCenterY = DEFAULT_CENTER_Y + 100; - - mInstrumentation.runOnMainSync(() -> { - Mockito.reset(mSpyController); - mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, - targetCenterX, targetCenterY); - mCurrentScale.set(mController.getScale()); - mCurrentCenterX.set(mController.getCenterX()); - mCurrentCenterY.set(mController.getCenterY()); - }); - - SystemClock.sleep(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - verifyStartValue(mScaleCaptor, mCurrentScale.get()); - verifyStartValue(mCenterXCaptor, mCurrentCenterX.get()); - verifyStartValue(mCenterYCaptor, mCurrentCenterY.get()); - verifyFinalSpec(targetScale, targetCenterX, targetCenterY); - } - - @Test - public void enableWindowMagnification_disabling_expectedStartAndEndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); - final float targetScale = DEFAULT_SCALE + 1.0f; - final float targetCenterX = DEFAULT_CENTER_X + 100; - final float targetCenterY = DEFAULT_CENTER_Y + 100; - - mInstrumentation.runOnMainSync( - () -> { - Mockito.reset(mSpyController); - mWindowMagnificationAnimationController.enableWindowMagnification(targetScale, - targetCenterX, targetCenterY); - mCurrentScale.set(mController.getScale()); - mCurrentCenterX.set(mController.getCenterX()); - mCurrentCenterY.set(mController.getCenterY()); - }); - SystemClock.sleep(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification( - mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - //Animating in reverse, so we only check if the start values are greater than current. - assertTrue(mScaleCaptor.getAllValues().get(0) > mCurrentScale.get()); - assertEquals(targetScale, mScaleCaptor.getValue(), 0f); - assertTrue(mCenterXCaptor.getAllValues().get(0) > mCurrentCenterX.get()); - assertEquals(targetCenterX, mCenterXCaptor.getValue(), 0f); - assertTrue(mCenterYCaptor.getAllValues().get(0) > mCurrentCenterY.get()); - assertEquals(targetCenterY, mCenterYCaptor.getValue(), 0f); - verifyFinalSpec(targetScale, targetCenterX, targetCenterY); - } - - @Test - public void enableWindowMagnificationWithSameScale_doNothing() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - verify(mSpyController, never()).enableWindowMagnification(anyFloat(), anyFloat(), - anyFloat()); - } - - @Test - public void setScale_enabled_expectedScale() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - mInstrumentation.runOnMainSync( - () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1)); - - verify(mSpyController).setScale(DEFAULT_SCALE + 1); - verifyFinalSpec(DEFAULT_SCALE + 1, DEFAULT_CENTER_X, DEFAULT_CENTER_Y); - } - - @Test - public void deleteWindowMagnification_enabled_expectedStartAndEndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - verify(mSpyController).deleteWindowMagnification(); - verifyStartValue(mScaleCaptor, DEFAULT_SCALE); - verifyStartValue(mCenterXCaptor, Float.NaN); - verifyStartValue(mCenterYCaptor, Float.NaN); - verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); - } - - @Test - public void deleteWindowMagnification_disabled_doNothing() { - deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - Mockito.verifyNoMoreInteractions(mSpyController); - } - - @Test - public void deleteWindowMagnification_enabling_checkStartAndEndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); - - //It just reverse the animation, so we don't need to wait the whole duration. - mInstrumentation.runOnMainSync( - () -> { - Mockito.reset(mSpyController); - mWindowMagnificationAnimationController.deleteWindowMagnification(); - mCurrentScale.set(mController.getScale()); - mCurrentCenterX.set(mController.getCenterX()); - mCurrentCenterY.set(mController.getCenterY()); - }); - SystemClock.sleep(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - verify(mSpyController).deleteWindowMagnification(); - - //The animation is in verse, so we only check the start values should no be greater than - // the current one. - assertTrue(mScaleCaptor.getAllValues().get(0) <= mCurrentScale.get()); - assertEquals(1.0f, mScaleCaptor.getValue(), 0f); - verifyStartValue(mCenterXCaptor, Float.NaN); - verifyStartValue(mCenterYCaptor, Float.NaN); - verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); - } - - @Test - public void deleteWindowMagnification_disabling_checkStartAndValues() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod); - - deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(), - mCenterXCaptor.capture(), mCenterYCaptor.capture()); - verify(mSpyController).deleteWindowMagnification(); - assertEquals(1.0f, mScaleCaptor.getValue(), 0f); - verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN); - } - - @Test - public void moveWindowMagnifier_enabled() { - enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod); - - mInstrumentation.runOnMainSync( - () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f)); - - verify(mSpyController).moveWindowMagnifier(100f, 200f); - verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f); - } - - @Test - public void onConfigurationChanged_passThrough() { - mWindowMagnificationAnimationController.onConfigurationChanged(100); - - verify(mSpyController).onConfigurationChanged(100); - } - private void verifyFinalSpec(float expectedScale, float expectedCenterX, - float expectedCenterY) { - assertEquals(expectedScale, mController.getScale(), 0f); - assertEquals(expectedCenterX, mController.getCenterX(), 0f); - assertEquals(expectedCenterY, mController.getCenterY(), 0f); - } - - private void enableWindowMagnificationAndWaitAnimating(long duration) { - mInstrumentation.runOnMainSync( - () -> { - Mockito.reset(mSpyController); - mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE, - DEFAULT_CENTER_X, DEFAULT_CENTER_Y); - }); - SystemClock.sleep(duration); - } - - private void deleteWindowMagnificationAndWaitAnimating(long duration) { - mInstrumentation.runOnMainSync( - () -> { - resetMockObjects(); - mWindowMagnificationAnimationController.deleteWindowMagnification(); - }); - SystemClock.sleep(duration); - } - - private void verifyStartValue(ArgumentCaptor<Float> captor, float startValue) { - assertEquals(startValue, captor.getAllValues().get(0), 0f); - } - - private void resetMockObjects() { - Mockito.reset(mSpyController); - } - - /** - * It observes the methods in {@link WindowMagnificationController} since we couldn't spy it - * directly. - */ - private static class SpyWindowMagnificationController extends WindowMagnificationController { - private WindowMagnificationController mSpyController; - - SpyWindowMagnificationController(Context context, Handler handler, - SfVsyncFrameCallbackProvider sfVsyncFrameProvider, - MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction, - WindowMagnifierCallback callback) { - super(context, handler, sfVsyncFrameProvider, mirrorWindowControl, transaction, - callback); - mSpyController = Mockito.mock(WindowMagnificationController.class); - } - - WindowMagnificationController getSpyController() { - return mSpyController; - } - - @Override - void enableWindowMagnification(float scale, float centerX, float centerY) { - super.enableWindowMagnification(scale, centerX, centerY); - mSpyController.enableWindowMagnification(scale, centerX, centerY); - } - - @Override - void deleteWindowMagnification() { - super.deleteWindowMagnification(); - mSpyController.deleteWindowMagnification(); - } - - @Override - void moveWindowMagnifier(float offsetX, float offsetY) { - super.moveWindowMagnifier(offsetX, offsetX); - mSpyController.moveWindowMagnifier(offsetX, offsetY); - } - - @Override - void setScale(float scale) { - super.setScale(scale); - mSpyController.setScale(scale); - } - - @Override - void onConfigurationChanged(int configDiff) { - super.onConfigurationChanged(configDiff); - mSpyController.onConfigurationChanged(configDiff); - } - - } - - private static ValueAnimator newValueAnimator() { - final ValueAnimator valueAnimator = new ValueAnimator(); - valueAnimator.setDuration(ANIMATION_DURATION_MS); - valueAnimator.setInterpolator(new AccelerateInterpolator(2.5f)); - valueAnimator.setFloatValues(0.0f, 1.0f); - return valueAnimator; - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 1515cec4c9e2..2007fbb8fc6c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -18,7 +18,6 @@ package com.android.systemui.accessibility; import static android.view.Choreographer.FrameCallback; -import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; @@ -84,8 +83,9 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { @After public void tearDown() { - mInstrumentation.runOnMainSync( - () -> mWindowMagnificationController.deleteWindowMagnification()); + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.deleteWindowMagnification(); + }); } @Test @@ -121,18 +121,4 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any()); } - - @Test - public void setScale_expectedValue() { - mInstrumentation.runOnMainSync(() -> { - mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, - Float.NaN); - }); - - mInstrumentation.runOnMainSync(() -> { - mWindowMagnificationController.setScale(3.0f); - }); - - assertEquals(3.0f, mWindowMagnificationController.getScale(), 0); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java index 936558bca2d2..41360130ac65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java @@ -26,7 +26,6 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.RemoteException; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.view.Display; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.IWindowMagnificationConnection; @@ -46,7 +45,6 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper public class WindowMagnificationTest extends SysuiTestCase { @Mock diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java index 694f51be4e30..f4c07004f632 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java @@ -24,14 +24,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.app.Instrumentation; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.systemui.model.SysUiState; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.wm.shell.common.DisplayController; @@ -46,12 +45,13 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class OneHandedGestureHandlerTest extends OneHandedTestCase { - Instrumentation mInstrumentation; OneHandedTouchHandler mTouchHandler; OneHandedTutorialHandler mTutorialHandler; OneHandedGestureHandler mGestureHandler; OneHandedManagerImpl mOneHandedManagerImpl; @Mock + CommandQueue mCommandQueue; + @Mock DisplayController mMockDisplayController; @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; @@ -62,12 +62,13 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); mTouchHandler = new OneHandedTouchHandler(); mTutorialHandler = new OneHandedTutorialHandler(mContext); mGestureHandler = Mockito.spy(new OneHandedGestureHandler( mContext, mMockDisplayController, mMockNavigationModeController)); - mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(), + mOneHandedManagerImpl = new OneHandedManagerImpl( + getContext(), + mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, @@ -100,6 +101,7 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase { @Test public void testOneHandedDisabled_shouldDisposeInputChannel() { mOneHandedManagerImpl.setOneHandedEnabled(false); + mOneHandedManagerImpl.setSwipeToNotificationEnabled(false); assertThat(mGestureHandler.mInputMonitor).isNull(); assertThat(mGestureHandler.mInputEventReceiver).isNull(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java index 3418ebf75e0c..763f6e4fe94b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java @@ -33,6 +33,7 @@ import android.view.Display; import androidx.test.filters.SmallTest; import com.android.systemui.model.SysUiState; +import com.android.systemui.statusbar.CommandQueue; import com.android.wm.shell.common.DisplayController; import org.junit.Before; @@ -51,6 +52,8 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { OneHandedTimeoutHandler mTimeoutHandler; @Mock + CommandQueue mCommandQueue; + @Mock DisplayController mMockDisplayController; @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; @@ -67,7 +70,9 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mDisplay = mContext.getDisplay(); - mOneHandedManagerImpl = new OneHandedManagerImpl(getContext(), + mOneHandedManagerImpl = new OneHandedManagerImpl( + getContext(), + mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mMockTouchHandler, @@ -94,14 +99,14 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { @Test public void testRegisterOrganizer() { - verify(mMockDisplayAreaOrganizer, times(1)).registerOrganizer(anyInt()); + verify(mMockDisplayAreaOrganizer).registerOrganizer(anyInt()); } @Test public void testStartOneHanded() { mOneHandedManagerImpl.startOneHanded(); - verify(mMockDisplayAreaOrganizer, times(1)).scheduleOffset(anyInt(), anyInt()); + verify(mMockDisplayAreaOrganizer).scheduleOffset(anyInt(), anyInt()); } @Test @@ -121,7 +126,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { public void testStopOneHanded_shouldRemoveTimer() { mOneHandedManagerImpl.stopOneHanded(); - verify(mTimeoutHandler, times(1)).removeTimer(); + verify(mTimeoutHandler).removeTimer(); } @Test @@ -129,7 +134,14 @@ public class OneHandedManagerImplTest extends OneHandedTestCase { final boolean enabled = true; mOneHandedManagerImpl.setOneHandedEnabled(enabled); - verify(mMockTouchHandler, atLeastOnce()).onOneHandedEnabled(enabled); + verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled); } + @Test + public void testUpdateSwipeToNotificationIsEnabled() { + final boolean enabled = true; + mOneHandedManagerImpl.setSwipeToNotificationEnabled(enabled); + + verify(mMockTouchHandler, times(2)).onOneHandedEnabled(enabled); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java index c157ae651cd5..f81d047b0f0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedSettingsUtilTest.java @@ -104,4 +104,10 @@ public class OneHandedSettingsUtilTest extends OneHandedTestCase { ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS, ONE_HANDED_TIMEOUT_LONG_IN_SECONDS); } + + @Test + public void testGetSettingsSwipeToNotificationEnabled() { + assertThat(mOneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + mContentResolver)).isAnyOf(true, false); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java index befa42a0acc9..04ebf25e1b49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTestCase.java @@ -32,6 +32,7 @@ public abstract class OneHandedTestCase extends SysuiTestCase { static boolean sOrigEnabled; static boolean sOrigTapsAppToExitEnabled; static int sOrigTimeout; + static boolean sOrigSwipeToNotification; @Before public void setupSettings() { @@ -41,12 +42,16 @@ public abstract class OneHandedTestCase extends SysuiTestCase { getContext().getContentResolver()); sOrigTapsAppToExitEnabled = OneHandedSettingsUtil.getSettingsTapsAppToExit( getContext().getContentResolver()); + sOrigSwipeToNotification = OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled( + getContext().getContentResolver()); Settings.Secure.putInt(getContext().getContentResolver(), Settings.Secure.ONE_HANDED_MODE_ENABLED, 1); Settings.Secure.putInt(getContext().getContentResolver(), Settings.Secure.ONE_HANDED_MODE_TIMEOUT, ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); Settings.Secure.putInt(getContext().getContentResolver(), Settings.Secure.TAPS_APP_TO_EXIT, 1); + Settings.Secure.putInt(getContext().getContentResolver(), + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); } @After @@ -57,6 +62,9 @@ public abstract class OneHandedTestCase extends SysuiTestCase { Settings.Secure.ONE_HANDED_MODE_TIMEOUT, sOrigTimeout); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.TAPS_APP_TO_EXIT, sOrigTapsAppToExitEnabled ? 1 : 0); + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, + sOrigSwipeToNotification ? 1 : 0); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java index fdb28d3d43b5..15881a2e7c18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java @@ -22,14 +22,13 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.app.Instrumentation; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.systemui.model.SysUiState; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.wm.shell.common.DisplayController; @@ -44,12 +43,13 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class OneHandedTouchHandlerTest extends OneHandedTestCase { - Instrumentation mInstrumentation; OneHandedTouchHandler mTouchHandler; OneHandedTutorialHandler mTutorialHandler; OneHandedGestureHandler mGestureHandler; OneHandedManagerImpl mOneHandedManagerImpl; @Mock + CommandQueue mCommandQueue; + @Mock DisplayController mMockDisplayController; @Mock NavigationModeController mMockNavigationModeController; @@ -61,11 +61,12 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); mTouchHandler = Mockito.spy(new OneHandedTouchHandler()); mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, mMockNavigationModeController); - mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(), + mOneHandedManagerImpl = new OneHandedManagerImpl( + getContext(), + mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java index f4aa00eaf02f..f2b77a0a936b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java @@ -19,14 +19,13 @@ package com.android.systemui.onehanded; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.app.Instrumentation; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; import com.android.systemui.model.SysUiState; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.NavigationModeController; import com.android.wm.shell.common.DisplayController; @@ -41,12 +40,13 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper public class OneHandedTutorialHandlerTest extends OneHandedTestCase { - Instrumentation mInstrumentation; OneHandedTouchHandler mTouchHandler; OneHandedTutorialHandler mTutorialHandler; OneHandedGestureHandler mGestureHandler; OneHandedManagerImpl mOneHandedManagerImpl; @Mock + CommandQueue mCommandQueue; + @Mock DisplayController mMockDisplayController; @Mock NavigationModeController mMockNavigationModeController; @@ -58,12 +58,13 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mInstrumentation = InstrumentationRegistry.getInstrumentation(); mTouchHandler = new OneHandedTouchHandler(); mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext)); mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController, mMockNavigationModeController); - mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(), + mOneHandedManagerImpl = new OneHandedManagerImpl( + getContext(), + mCommandQueue, mMockDisplayController, mMockDisplayAreaOrganizer, mTouchHandler, diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java index ffedb07b8db4..6db2679ea116 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java @@ -28,7 +28,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; -import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.ScreenLifecycle; import com.android.systemui.statusbar.CommandQueue; @@ -53,8 +52,6 @@ public class OneHandedUITest extends OneHandedTestCase { @Mock OneHandedManagerImpl mMockOneHandedManagerImpl; @Mock - DumpManager mMockDumpManager; - @Mock OneHandedSettingsUtil mMockSettingsUtil; @Mock OneHandedTimeoutHandler mMockTimeoutHandler; @@ -68,7 +65,6 @@ public class OneHandedUITest extends OneHandedTestCase { mOneHandedUI = new OneHandedUI(mContext, mCommandQueue, mMockOneHandedManagerImpl, - mMockDumpManager, mMockSettingsUtil, mScreenLifecycle); mOneHandedUI.start(); @@ -168,6 +164,18 @@ public class OneHandedUITest extends OneHandedTestCase { OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS); } + @Test + public void tesSettingsObserver_updateSwipeToNotification() { + // Bypass test if device not support one-handed mode + if (!mIsSupportOneHandedMode) { + return; + } + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 1); + + verify(mMockOneHandedManagerImpl).setSwipeToNotificationEnabled(true); + } + @Ignore("Clarifying do not receive callback") @Test public void testKeyguardBouncerShowing_shouldStopOneHanded() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java index 548da8e1f2aa..35620329467b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java @@ -384,7 +384,7 @@ public class PowerUITest extends SysuiTestCase { mPowerUI.mSevereWarningShownThisChargeCycle = false; BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); - // sanity check to make sure we can show for a valid config + // readiness check to make sure we can show for a valid config state.mBatteryLevel = 10; state.mTimeRemainingMillis = Duration.ofHours(2).toMillis(); boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); @@ -449,7 +449,7 @@ public class PowerUITest extends SysuiTestCase { mPowerUI.mSevereWarningShownThisChargeCycle = false; BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper(); - // sanity check to make sure we can show for a valid config + // readiness check to make sure we can show for a valid config state.mBatteryLevel = 1; state.mTimeRemainingMillis = Duration.ofMinutes(1).toMillis(); boolean shouldShow = mPowerUI.shouldShowHybridWarning(state.get()); @@ -572,7 +572,7 @@ public class PowerUITest extends SysuiTestCase { state.mIsHybrid = false; BatteryStateSnapshot lastState = state.get(); - // sanity check to make sure we can show for a valid config + // readiness check to make sure we can show for a valid config state.mBatteryLevel = 10; state.mBucket = -1; boolean shouldShow = mPowerUI.shouldShowLowBatteryWarning(state.get(), lastState); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java index b5060ee416f7..1fb28f0878bd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java @@ -65,9 +65,9 @@ public class NavigationBarContextTest extends SysuiTestCase { mDependency.injectMockDependency(AssistManager.class); mGroup = new ContextualButtonGroup(GROUP_ID); - mBtn0 = new ContextualButton(BUTTON_0_ID, ICON_RES_ID); - mBtn1 = new ContextualButton(BUTTON_1_ID, ICON_RES_ID); - mBtn2 = new ContextualButton(BUTTON_2_ID, ICON_RES_ID); + mBtn0 = new ContextualButton(BUTTON_0_ID, mContext, ICON_RES_ID); + mBtn1 = new ContextualButton(BUTTON_1_ID, mContext, ICON_RES_ID); + mBtn2 = new ContextualButton(BUTTON_2_ID, mContext, ICON_RES_ID); // Order of adding buttons to group determines the priority, ascending priority order mGroup.addButton(mBtn0); diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 9ad808a685a6..a167ab16f944 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -148,6 +148,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; + boolean mRequestFilterKeyEvents; boolean mRetrieveInteractiveWindows; @@ -325,8 +327,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0; mRequestMultiFingerGestures = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0; - mRequestFilterKeyEvents = (info.flags - & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; + mRequestTwoFingerPassthrough = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0; + mRequestFilterKeyEvents = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; mRetrieveInteractiveWindows = (info.flags & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; mCaptureFingerprintGestures = (info.flags @@ -1772,6 +1776,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return mRequestMultiFingerGestures; } + public boolean isTwoFingerPassthroughEnabled() { + return mRequestTwoFingerPassthrough; + } + @Override public void setGestureDetectionPassthroughRegion(int displayId, Region region) { mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 8b40f610b4b3..cd9ab8db0854 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -118,6 +118,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100; + /** + * Flag for enabling multi-finger gestures. + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x00000200; + static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS | FLAG_FEATURE_AUTOCLICK @@ -125,7 +132,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER | FLAG_SERVICE_HANDLES_DOUBLE_TAP - | FLAG_REQUEST_MULTI_FINGER_GESTURES; + | FLAG_REQUEST_MULTI_FINGER_GESTURES + | FLAG_REQUEST_2_FINGER_PASSTHROUGH; private final Context mContext; @@ -421,6 +429,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { explorer.setMultiFingerGesturesEnabled(true); } + if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) { + explorer.setTwoFingerPassthroughEnabled(true); + } addFirstEventHandler(displayId, explorer); mTouchExplorer.put(displayId, explorer); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index b1340228ffa0..833aeecc4c47 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1837,6 +1837,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isMultiFingerGesturesEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; } + if (userState.isTwoFingerPassthroughEnabledLocked()) { + flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH; + } } if (userState.isFilterKeyEventsEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; @@ -2120,6 +2123,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); boolean serviceHandlesDoubleTapEnabled = false; boolean requestMultiFingerGestures = false; + boolean requestTwoFingerPassthrough = false; final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); @@ -2127,6 +2131,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub touchExplorationEnabled = true; serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); + requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled(); break; } } @@ -2143,6 +2148,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); + userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); } private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index f865aa7d6e37..4c9e44403026 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -110,6 +110,7 @@ class AccessibilityUserState { private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; private int mUserInteractiveUiTimeout; private int mUserNonInteractiveUiTimeout; private int mNonInteractiveUiTimeout = 0; @@ -169,6 +170,7 @@ class AccessibilityUserState { mIsTouchExplorationEnabled = false; mServiceHandlesDoubleTap = false; mRequestMultiFingerGestures = false; + mRequestTwoFingerPassthrough = false; mIsDisplayMagnificationEnabled = false; mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; @@ -456,6 +458,8 @@ class AccessibilityUserState { .append(String.valueOf(mServiceHandlesDoubleTap)); pw.append(", requestMultiFingerGestures=") .append(String.valueOf(mRequestMultiFingerGestures)); + pw.append(", requestTwoFingerPassthrough=") + .append(String.valueOf(mRequestTwoFingerPassthrough)); pw.append(", displayMagnificationEnabled=").append(String.valueOf( mIsDisplayMagnificationEnabled)); pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled)); @@ -790,6 +794,14 @@ class AccessibilityUserState { public void setMultiFingerGesturesLocked(boolean enabled) { mRequestMultiFingerGestures = enabled; } + public boolean isTwoFingerPassthroughEnabledLocked() { + return mRequestTwoFingerPassthrough; + } + + public void setTwoFingerPassthroughLocked(boolean enabled) { + mRequestTwoFingerPassthrough = enabled; + } + public int getUserInteractiveUiTimeoutLocked() { return mUserInteractiveUiTimeout; diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java index e9c70c60a322..8604fe7a7359 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -94,8 +94,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener { private boolean mServiceHandlesDoubleTap = false; // Whether multi-finger gestures are enabled. boolean mMultiFingerGesturesEnabled; + // Whether the two-finger passthrough is enabled when multi-finger gestures are enabled. + private boolean mTwoFingerPassthroughEnabled; // A list of all the multi-finger gestures, for easy adding and removal. private final List<GestureMatcher> mMultiFingerGestures = new ArrayList<>(); + // A list of two-finger swipes, for easy adding and removal when turning on or off two-finger + // passthrough. + private final List<GestureMatcher> mTwoFingerSwipes = new ArrayList<>(); // Shared state information. private TouchState mState; @@ -105,6 +110,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mListener = listener; mState = state; mMultiFingerGesturesEnabled = false; + mTwoFingerPassthroughEnabled = false; // Set up gestures. // Start with double tap. mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this)); @@ -161,14 +167,14 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mMultiFingerGestures.add( new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this)); // Two-finger swipes. - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, LEFT, GESTURE_2_FINGER_SWIPE_LEFT, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, RIGHT, GESTURE_2_FINGER_SWIPE_RIGHT, this)); - mMultiFingerGestures.add( - new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mTwoFingerSwipes.add(new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mMultiFingerGestures.addAll(mTwoFingerSwipes); // Three-finger swipes. mMultiFingerGestures.add( new MultiFingerSwipe(context, 3, DOWN, GESTURE_3_FINGER_SWIPE_DOWN, this)); @@ -360,6 +366,25 @@ class GestureManifold implements GestureMatcher.StateChangeListener { } } + public boolean isTwoFingerPassthroughEnabled() { + return mTwoFingerPassthroughEnabled; + } + + public void setTwoFingerPassthroughEnabled(boolean mode) { + if (mTwoFingerPassthroughEnabled != mode) { + mTwoFingerPassthroughEnabled = mode; + if (!mode) { + mMultiFingerGestures.addAll(mTwoFingerSwipes); + if (mMultiFingerGesturesEnabled) { + mGestures.addAll(mTwoFingerSwipes); + } + } else { + mMultiFingerGestures.removeAll(mTwoFingerSwipes); + mGestures.removeAll(mTwoFingerSwipes); + } + } + } + public void setServiceHandlesDoubleTap(boolean mode) { mServiceHandlesDoubleTap = mode; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 696702fad730..e1baefed4425 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -41,6 +41,7 @@ import android.annotation.NonNull; import android.content.Context; import android.graphics.Region; import android.os.Handler; +import android.util.DisplayMetrics; import android.util.Slog; import android.view.InputDevice; import android.view.MotionEvent; @@ -91,12 +92,21 @@ public class TouchExplorer extends BaseEventStreamTransformation // The timeout after which we are no longer trying to detect a gesture. private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000; + // The height of the top and bottom edges for edge-swipes. + // For now this is only used to allow three-finger edge-swipes from the bottom. + private static final float EDGE_SWIPE_HEIGHT_CM = 0.25f; + + // The calculated edge height for the top and bottom edges. + private final float mEdgeSwipeHeightPixels; // Timeout before trying to decide what the user is trying to do. private final int mDetermineUserIntentTimeout; // Slop between the first and second tap to be a double tap. private final int mDoubleTapSlop; + // Slop to move before being considered a move rather than a tap. + private final int mTouchSlop; + // The current state of the touch explorer. private TouchState mState; @@ -174,6 +184,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher = new EventDispatcher(context, mAms, super.getNext(), mState); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); + mEdgeSwipeHeightPixels = metrics.ydpi / GestureUtils.CM_PER_INCH * EDGE_SWIPE_HEIGHT_CM; mHandler = mainHandler; mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed(); mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed(); @@ -219,16 +232,10 @@ public class TouchExplorer extends BaseEventStreamTransformation if (mState.isTouchExploring()) { // If a touch exploration gesture is in progress send events for its end. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); - } else if (mState.isDragging()) { - mDraggingPointerId = INVALID_POINTER_ID; - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isDelegating()) { - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isGestureDetecting()) { - // No state specific cleanup required. } + mDraggingPointerId = INVALID_POINTER_ID; + // Send exit to any pointers that we have delivered as part of delegating or dragging. + mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); // Remove all pending callbacks. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); @@ -554,7 +561,26 @@ public class TouchExplorer extends BaseEventStreamTransformation // stream consistent. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } + if (mGestureDetector.isMultiFingerGesturesEnabled() + && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (event.getPointerCount() == 3) { + boolean isOnBottomEdge = false; + // If three fingers go down on the bottom edge of the screen, delegate immediately. + final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels; + for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) { + if (mReceivedPointerTracker.getReceivedPointerDownY(i) + > (screenHeight - mEdgeSwipeHeightPixels)) { + isOnBottomEdge = true; + } + } + if (isOnBottomEdge) { + mState.startDelegating(); + mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); + } + } + } } + /** * Handles ACTION_MOVE while in the touch interacting state. This is where transitions to * delegating and dragging states are handled. @@ -563,7 +589,7 @@ public class TouchExplorer extends BaseEventStreamTransformation MotionEvent event, MotionEvent rawEvent, int policyFlags) { final int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); final int pointerIndex = event.findPointerIndex(pointerId); - final int pointerIdBits = (1 << pointerId); + int pointerIdBits = (1 << pointerId); switch (event.getPointerCount()) { case 1: // We have not started sending events since we try to @@ -574,12 +600,26 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } // Make sure we don't have any pending transitions to touch exploration mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); + if (mGestureDetector.isMultiFingerGesturesEnabled() + && mGestureDetector.isTwoFingerPassthroughEnabled()) { + final float deltaX = + mReceivedPointerTracker.getReceivedPointerDownX(pointerId) + - rawEvent.getX(pointerIndex); + final float deltaY = + mReceivedPointerTracker.getReceivedPointerDownY(pointerId) + - rawEvent.getY(pointerIndex); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < mTouchSlop) { + return; + } + } // More than one pointer so the user is not touch exploring // and now we have to decide whether to delegate or drag. // Remove move history before send injected non-move events @@ -588,8 +628,8 @@ public class TouchExplorer extends BaseEventStreamTransformation // Two pointers moving in the same direction within // a given distance perform a drag. mState.startDragging(); - mDraggingPointerId = pointerId; adjustEventLocationForDrag(event); + pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( event, ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); @@ -648,7 +688,8 @@ public class TouchExplorer extends BaseEventStreamTransformation event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } if (mSendHoverEnterAndMoveDelayed.isPending()) { @@ -703,7 +744,8 @@ public class TouchExplorer extends BaseEventStreamTransformation */ private void handleMotionEventStateDragging( MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { // Multi-finger gestures conflict with this functionality. return; } @@ -756,6 +798,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // The two pointers are moving either in different directions or // no close enough => delegate the gesture to the view hierarchy. mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; // Remove move history before send injected non-move events event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. @@ -767,6 +810,7 @@ public class TouchExplorer extends BaseEventStreamTransformation break; default: mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( @@ -784,15 +828,16 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; case ACTION_UP: - mAms.onTouchInteractionEnd(); - // Announce the end of a new touch interaction. - mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); if (event.getPointerId(GestureUtils.getActionIndex(event)) == mDraggingPointerId) { mDraggingPointerId = INVALID_POINTER_ID; // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( event, ACTION_UP, rawEvent, pointerIdBits, policyFlags); } + mAms.onTouchInteractionEnd(); + // Announce the end of a new touch interaction. + mDispatcher.sendAccessibilityEvent(TYPE_TOUCH_INTERACTION_END); + break; } } @@ -911,21 +956,55 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag The new location will be in - * between the two fingers touching the screen. + * Adjust the location of an injected event when performing a drag. The location will be the + * location of the finger closest to an edge of the screen. */ private void adjustEventLocationForDrag(MotionEvent event) { - final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); + final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); - final int pointerIndex = event.findPointerIndex(mDraggingPointerId); - final float deltaX = - (pointerIndex == 0) ? (secondPtrX - firstPtrX) : (firstPtrX - secondPtrX); - final float deltaY = - (pointerIndex == 0) ? (secondPtrY - firstPtrY) : (firstPtrY - secondPtrY); - event.offsetLocation(deltaX / 2, deltaY / 2); + final int secondPtrId = event.getPointerId(1); + float draggingX; + float draggingY; + if (mDraggingPointerId == INVALID_POINTER_ID) { + // The goal is to use the coordinates of the finger that is closest to its closest edge. + if (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { + draggingX = firstPtrX; + draggingY = firstPtrY; + mDraggingPointerId = firstPtrId; + } else { + draggingX = secondPtrX; + draggingY = secondPtrY; + mDraggingPointerId = secondPtrId; + } + } else { + // Just use the coordinates of the dragging pointer. + int pointerIndex = event.findPointerIndex(mDraggingPointerId); + draggingX = event.getX(pointerIndex); + draggingY = event.getY(pointerIndex); + } + event.setLocation(draggingX, draggingY); + } + + private float getDistanceToClosestEdge(float x, float y) { + final long width = mContext.getResources().getDisplayMetrics().widthPixels; + final long height = mContext.getResources().getDisplayMetrics().heightPixels; + float distance = Float.MAX_VALUE; + if (x < (width - x)) { + distance = x; + } else { + distance = width - x; + } + if (distance > y) { + distance = y; + } + if (distance > (height - y)) { + distance = (height - y); + } + return distance; } public TouchState getState() { @@ -954,6 +1033,13 @@ public class TouchExplorer extends BaseEventStreamTransformation mGestureDetector.setMultiFingerGesturesEnabled(enabled); } + /** + * This function turns on and off two-finger passthrough gestures such as drag and pinch when + * multi-finger gestures are enabled. + */ + public void setTwoFingerPassthroughEnabled(boolean enabled) { + mGestureDetector.setTwoFingerPassthroughEnabled(enabled); + } public void setGestureDetectionPassthroughRegion(Region region) { mGestureDetectionPassthroughRegion = region; } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java index 3ee5b28ee338..bd25f2bea881 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java @@ -25,12 +25,10 @@ import static java.util.Arrays.copyOfRange; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Point; import android.provider.Settings; import android.util.Log; import android.util.MathUtils; import android.util.Slog; -import android.view.Display; import android.view.MotionEvent; import com.android.internal.annotations.VisibleForTesting; @@ -92,8 +90,6 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private final int mDisplayId; - private final Context mContext; - private final Point mTempPoint = new Point(); private final Queue<MotionEvent> mDebugOutputEventHistory; @@ -111,7 +107,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl Slog.i(LOG_TAG, "WindowMagnificationGestureHandler() , displayId = " + displayId + ")"); } - mContext = context; + mWindowMagnificationMgr = windowMagnificationMgr; mDetectShortcutTrigger = detectShortcutTrigger; mDisplayId = displayId; @@ -188,14 +184,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (!mDetectShortcutTrigger) { return; } - final Point screenSize = mTempPoint; - getScreenSize(mTempPoint); - toggleMagnification(screenSize.x / 2.0f, screenSize.y / 2.0f); - } - - private void getScreenSize(Point outSize) { - final Display display = mContext.getDisplay(); - display.getRealSize(outSize); + toggleMagnification(Float.NaN, Float.NaN); } @Override diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 12e6e10d9047..186812bc15c7 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -1239,9 +1239,10 @@ public class BackupManagerService extends IBackupManager.Stub { @Override public IRestoreSession beginRestoreSessionForUser( - int userId, String packageName, String transportID) throws RemoteException { + int userId, String packageName, String transportID, + @OperationType int operationType) throws RemoteException { return isUserReadyForBackup(userId) - ? beginRestoreSession(userId, packageName, transportID) : null; + ? beginRestoreSession(userId, packageName, transportID, operationType) : null; } /** @@ -1250,13 +1251,15 @@ public class BackupManagerService extends IBackupManager.Stub { */ @Nullable public IRestoreSession beginRestoreSession( - @UserIdInt int userId, String packageName, String transportName) { + @UserIdInt int userId, String packageName, String transportName, + @OperationType int operationType) { UserBackupManagerService userBackupManagerService = getServiceForUserIfCallerHasPermission(userId, "beginRestoreSession()"); return userBackupManagerService == null ? null - : userBackupManagerService.beginRestoreSession(packageName, transportName); + : userBackupManagerService.beginRestoreSession(packageName, transportName, + operationType); } @Override diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java index c9b09e31f94b..0855b9d8f675 100644 --- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java +++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java @@ -10,6 +10,7 @@ import static com.android.server.backup.UserBackupManagerService.OP_TYPE_BACKUP_ import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; +import android.app.backup.BackupManager; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; import android.app.backup.IBackupCallback; @@ -146,7 +147,8 @@ public class KeyValueAdbBackupEngine { private IBackupAgent bindToAgent(ApplicationInfo targetApp) { try { return mBackupManagerService.bindToAgentSynchronous(targetApp, - ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); + ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, + BackupManager.OperationType.BACKUP); } catch (SecurityException e) { Slog.e(TAG, "error in binding to agent for package " + targetApp.packageName + ". " + e); diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 3ab81cbb313f..29235dd1ee72 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -1651,13 +1651,15 @@ public class UserBackupManagerService { /** Fires off a backup agent, blocking until it attaches or times out. */ @Nullable - public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode) { + public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode, + @OperationType int operationType) { IBackupAgent agent = null; synchronized (mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; try { - if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId)) { + if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId, + operationType)) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app)); // success; wait for the agent to arrive @@ -3973,7 +3975,8 @@ public class UserBackupManagerService { restoreSet, packageName, token, - listener); + listener, + mScheduledBackupEligibility); mBackupHandler.sendMessage(msg); } catch (Exception e) { // Calling into the transport broke; back off and proceed with the installation. @@ -4002,13 +4005,15 @@ public class UserBackupManagerService { } /** Hand off a restore session. */ - public IRestoreSession beginRestoreSession(String packageName, String transport) { + public IRestoreSession beginRestoreSession(String packageName, String transport, + @OperationType int operationType) { if (DEBUG) { Slog.v( TAG, addUserIdToLogMessage( mUserId, - "beginRestoreSession: pkg=" + packageName + " transport=" + transport)); + "beginRestoreSession: pkg=" + packageName + " transport=" + transport + + "operationType=" + operationType)); } boolean needPermission = true; @@ -4065,7 +4070,8 @@ public class UserBackupManagerService { "Restore session requested but currently running backups")); return null; } - mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport); + mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport, + getEligibilityRulesForOperation(operationType)); mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, mAgentTimeoutParameters.getRestoreAgentTimeoutMillis()); } diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java index 846c6a23d394..fe5497f3eb94 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java +++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java @@ -41,6 +41,7 @@ import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.remote.RemoteCall; +import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.backup.utils.FullBackupUtils; import java.io.File; @@ -64,6 +65,7 @@ public class FullBackupEngine { private final int mOpToken; private final int mTransportFlags; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; + private final BackupEligibilityRules mBackupEligibilityRules; class FullBackupRunner implements Runnable { private final @UserIdInt int mUserId; @@ -190,7 +192,8 @@ public class FullBackupEngine { BackupRestoreTask timeoutMonitor, long quota, int opToken, - int transportFlags) { + int transportFlags, + BackupEligibilityRules backupEligibilityRules) { this.backupManagerService = backupManagerService; mOutput = output; mPreflightHook = preflightHook; @@ -204,6 +207,7 @@ public class FullBackupEngine { Objects.requireNonNull( backupManagerService.getAgentTimeoutParameters(), "Timeout parameters cannot be null"); + mBackupEligibilityRules = backupEligibilityRules; } public int preflightCheck() throws RemoteException { @@ -302,7 +306,8 @@ public class FullBackupEngine { } mAgent = backupManagerService.bindToAgentSynchronous( - mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL); + mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL, + mBackupEligibilityRules.getOperationType()); } return mAgent != null; } diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java index 0a117746ea3f..448e0860b88d 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java @@ -421,7 +421,8 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor this, Long.MAX_VALUE, mCurrentOpToken, - /*transportFlags=*/ 0); + /*transportFlags=*/ 0, + mBackupEligibilityRules); sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName); // Don't need to check preflight result as there is no preflight hook. diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 1fa88920ca74..a4d47d492451 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -860,7 +860,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba this, mQuota, mCurrentOpToken, - mTransportFlags); + mTransportFlags, + mBackupEligibilityRules); try { try { if (!mIsCancelled) { diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index 1bb434950563..100dbae9f01d 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -305,8 +305,7 @@ public class BackupHandler extends Handler { params.isSystemRestore, params.filterSet, params.listener, - backupManagerService.getEligibilityRulesForOperation( - OperationType.BACKUP)); + params.backupEligibilityRules); synchronized (backupManagerService.getPendingRestores()) { if (backupManagerService.isRestoreInProgress()) { diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index 6124171c7a0e..7267cdf8539c 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -731,7 +731,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { try { agent = mBackupManagerService.bindToAgentSynchronous( - packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL); + packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL, + mBackupEligibilityRules.getOperationType()); if (agent == null) { mReporter.onAgentError(packageName); throw AgentException.transitory(); diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java index a6fea6cc75a0..a08a1f8d5387 100644 --- a/services/backup/java/com/android/server/backup/params/RestoreParams.java +++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java @@ -23,6 +23,7 @@ import android.content.pm.PackageInfo; import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.transport.TransportClient; +import com.android.server.backup.utils.BackupEligibilityRules; import java.util.Map; import java.util.Set; @@ -37,6 +38,7 @@ public class RestoreParams { public final boolean isSystemRestore; @Nullable public final String[] filterSet; public final OnTaskFinishedListener listener; + public final BackupEligibilityRules backupEligibilityRules; /** * No kill after restore. @@ -47,7 +49,8 @@ public class RestoreParams { IBackupManagerMonitor monitor, long token, PackageInfo packageInfo, - OnTaskFinishedListener listener) { + OnTaskFinishedListener listener, + BackupEligibilityRules eligibilityRules) { return new RestoreParams( transportClient, observer, @@ -57,7 +60,8 @@ public class RestoreParams { /* pmToken */ 0, /* isSystemRestore */ false, /* filterSet */ null, - listener); + listener, + eligibilityRules); } /** @@ -70,7 +74,8 @@ public class RestoreParams { long token, String packageName, int pmToken, - OnTaskFinishedListener listener) { + OnTaskFinishedListener listener, + BackupEligibilityRules backupEligibilityRules) { String[] filterSet = {packageName}; return new RestoreParams( transportClient, @@ -81,7 +86,8 @@ public class RestoreParams { pmToken, /* isSystemRestore */ false, filterSet, - listener); + listener, + backupEligibilityRules); } /** @@ -92,7 +98,8 @@ public class RestoreParams { IRestoreObserver observer, IBackupManagerMonitor monitor, long token, - OnTaskFinishedListener listener) { + OnTaskFinishedListener listener, + BackupEligibilityRules backupEligibilityRules) { return new RestoreParams( transportClient, observer, @@ -102,7 +109,8 @@ public class RestoreParams { /* pmToken */ 0, /* isSystemRestore */ true, /* filterSet */ null, - listener); + listener, + backupEligibilityRules); } /** @@ -115,7 +123,8 @@ public class RestoreParams { long token, String[] filterSet, boolean isSystemRestore, - OnTaskFinishedListener listener) { + OnTaskFinishedListener listener, + BackupEligibilityRules backupEligibilityRules) { return new RestoreParams( transportClient, observer, @@ -125,7 +134,8 @@ public class RestoreParams { /* pmToken */ 0, isSystemRestore, filterSet, - listener); + listener, + backupEligibilityRules); } private RestoreParams( @@ -137,7 +147,8 @@ public class RestoreParams { int pmToken, boolean isSystemRestore, @Nullable String[] filterSet, - OnTaskFinishedListener listener) { + OnTaskFinishedListener listener, + BackupEligibilityRules backupEligibilityRules) { this.transportClient = transportClient; this.observer = observer; this.monitor = monitor; @@ -147,5 +158,6 @@ public class RestoreParams { this.isSystemRestore = isSystemRestore; this.filterSet = filterSet; this.listener = listener; + this.backupEligibilityRules = backupEligibilityRules; } } diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java index 5a57cdc39402..3102b5f4a04d 100644 --- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java +++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java @@ -42,6 +42,7 @@ import com.android.server.backup.internal.OnTaskFinishedListener; import com.android.server.backup.params.RestoreGetSetsParams; import com.android.server.backup.params.RestoreParams; import com.android.server.backup.transport.TransportClient; +import com.android.server.backup.utils.BackupEligibilityRules; import java.util.function.BiFunction; @@ -55,6 +56,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { private final String mTransportName; private final UserBackupManagerService mBackupManagerService; private final int mUserId; + private final BackupEligibilityRules mBackupEligibilityRules; @Nullable private final String mPackageName; public RestoreSet[] mRestoreSets = null; boolean mEnded = false; @@ -63,12 +65,14 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { public ActiveRestoreSession( UserBackupManagerService backupManagerService, @Nullable String packageName, - String transportName) { + String transportName, + BackupEligibilityRules backupEligibilityRules) { mBackupManagerService = backupManagerService; mPackageName = packageName; mTransportManager = backupManagerService.getTransportManager(); mTransportName = transportName; mUserId = backupManagerService.getUserId(); + mBackupEligibilityRules = backupEligibilityRules; } public void markTimedOut() { @@ -178,7 +182,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { observer, monitor, token, - listener), + listener, + mBackupEligibilityRules), "RestoreSession.restoreAll()"); } finally { Binder.restoreCallingIdentity(oldId); @@ -271,7 +276,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { token, packages, /* isSystemRestore */ packages.length > 1, - listener), + listener, + mBackupEligibilityRules), "RestoreSession.restorePackages(" + packages.length + " packages)"); } finally { Binder.restoreCallingIdentity(oldId); @@ -363,7 +369,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { monitor, token, app, - listener), + listener, + mBackupEligibilityRules), "RestoreSession.restorePackage(" + packageName + ")"); } finally { Binder.restoreCallingIdentity(oldId); diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index e42d3bd0e352..622067999f27 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -49,6 +49,7 @@ import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; +import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.backup.utils.BytesReadListener; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; import com.android.server.backup.utils.RestoreUtils; @@ -129,11 +130,13 @@ public class FullRestoreEngine extends RestoreEngine { private final boolean mIsAdbRestore; @GuardedBy("mPipesLock") private boolean mPipesClosed; + private final BackupEligibilityRules mBackupEligibilityRules; public FullRestoreEngine(UserBackupManagerService backupManagerService, BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer, IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks, - int ephemeralOpToken, boolean isAdbRestore) { + int ephemeralOpToken, boolean isAdbRestore, + BackupEligibilityRules backupEligibilityRules) { mBackupManagerService = backupManagerService; mEphemeralOpToken = ephemeralOpToken; mMonitorTask = monitorTask; @@ -147,6 +150,7 @@ public class FullRestoreEngine extends RestoreEngine { "Timeout parameters cannot be null"); mIsAdbRestore = isAdbRestore; mUserId = backupManagerService.getUserId(); + mBackupEligibilityRules = backupEligibilityRules; } public IBackupAgent getAgent() { @@ -365,7 +369,8 @@ public class FullRestoreEngine extends RestoreEngine { mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL - : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL); + : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, + mBackupEligibilityRules.getOperationType()); mAgentPackage = pkg; } catch (IOException | NameNotFoundException e) { // fall through to error handling diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index 923bb086f914..c94286ffcffa 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -25,12 +25,15 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEA import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION; import android.app.backup.IFullBackupRestoreObserver; +import android.content.pm.PackageManagerInternal; import android.os.ParcelFileDescriptor; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.fullbackup.FullBackupObbConnection; +import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.backup.utils.FullBackupRestoreObserverUtils; import com.android.server.backup.utils.PasswordUtils; @@ -102,7 +105,10 @@ public class PerformAdbRestoreTask implements Runnable { } FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService, null, - mObserver, null, null, true, 0 /*unused*/, true); + mObserver, null, null, true, 0 /*unused*/, true, + BackupEligibilityRules.forBackup(mBackupManagerService.getPackageManager(), + LocalServices.getService(PackageManagerInternal.class), + mBackupManagerService.getUserId())); FullRestoreEngineThread mEngineThread = new FullRestoreEngineThread(mEngine, tarInputStream); mEngineThread.run(); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index a7e360403ccc..7baf55992770 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -162,6 +162,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { private final int mEphemeralOpToken; private final BackupAgentTimeoutParameters mAgentTimeoutParameters; + private final BackupEligibilityRules mBackupEligibilityRules; @VisibleForTesting PerformUnifiedRestoreTask(UserBackupManagerService backupManagerService) { @@ -171,6 +172,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mTransportManager = null; mEphemeralOpToken = 0; mUserId = 0; + mBackupEligibilityRules = null; this.backupManagerService = backupManagerService; } @@ -208,6 +210,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mAgentTimeoutParameters = Objects.requireNonNull( backupManagerService.getAgentTimeoutParameters(), "Timeout parameters cannot be null"); + mBackupEligibilityRules = backupEligibilityRules; if (targetPackage != null) { // Single package restore @@ -656,7 +659,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Good to go! Set up and bind the agent... mAgent = backupManagerService.bindToAgentSynchronous( mCurrentPackage.applicationInfo, - ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL); + ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, + mBackupEligibilityRules.getOperationType()); if (mAgent == null) { Slog.w(TAG, "Can't find backup agent for " + packageName); mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, @@ -913,7 +917,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { mCurrentPackage.packageName); mEngine = new FullRestoreEngine(backupManagerService, this, null, - mMonitor, mCurrentPackage, false, mEphemeralOpToken, false); + mMonitor, mCurrentPackage, false, mEphemeralOpToken, false, + mBackupEligibilityRules); mEngineThread = new FullRestoreEngineThread(mEngine, mEnginePipes[0]); ParcelFileDescriptor eWriteEnd = mEnginePipes[1]; diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java index ee05c2b9ea3b..d6598975a647 100644 --- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java +++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java @@ -318,4 +318,8 @@ public class BackupEligibilityRules { return true; } } + + public int getOperationType() { + return mOperationType; + } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 02c08cc4cd39..ef62a991f323 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -220,6 +220,8 @@ import com.android.server.utils.PriorityDump; import com.google.android.collect.Lists; +import libcore.io.IoUtils; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -7513,18 +7515,34 @@ public class ConnectivityService extends IConnectivityManager.Stub public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId, int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr, String dstAddr) { - mKeepaliveTracker.startNattKeepalive( - getNetworkAgentInfoForNetwork(network), fd, resourceId, - intervalSeconds, cb, - srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT); + try { + mKeepaliveTracker.startNattKeepalive( + getNetworkAgentInfoForNetwork(network), fd, resourceId, + intervalSeconds, cb, + srcAddr, dstAddr, NattSocketKeepalive.NATT_PORT); + } finally { + // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. + // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately. + if (fd != null && Binder.getCallingPid() != Process.myPid()) { + IoUtils.closeQuietly(fd); + } + } } @Override public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds, ISocketKeepaliveCallback cb) { - enforceKeepalivePermission(); - mKeepaliveTracker.startTcpKeepalive( - getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb); + try { + enforceKeepalivePermission(); + mKeepaliveTracker.startTcpKeepalive( + getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb); + } finally { + // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. + // startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately. + if (fd != null && Binder.getCallingPid() != Process.myPid()) { + IoUtils.closeQuietly(fd); + } + } } @Override diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index df9dee89f5a2..6dbb1e922f60 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -137,6 +137,7 @@ final class UiModeManagerService extends SystemService { int mCurUiMode = 0; private int mSetUiMode = 0; private boolean mHoldingConfiguration = false; + private int mCurrentUser; private Configuration mConfiguration = new Configuration(); boolean mSystemReady; @@ -325,6 +326,7 @@ final class UiModeManagerService extends SystemService { @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { + mCurrentUser = to.getUserIdentifier(); getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver); verifySetupWizardCompleted(); } @@ -727,16 +729,30 @@ final class UiModeManagerService extends SystemService { @Override public boolean setNightModeActivated(boolean active) { + if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) + != PackageManager.PERMISSION_GRANTED)) { + Slog.e(TAG, "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission"); + return false; + } + final int user = Binder.getCallingUserHandle().getIdentifier(); + if (user != mCurrentUser && getContext().checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS) + != PackageManager.PERMISSION_GRANTED) { + Slog.e(TAG, "Target user is not current user," + + " INTERACT_ACROSS_USERS permission is required"); + return false; + + } synchronized (mLock) { - final int user = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) { unregisterScreenOffEventLocked(); mOverrideNightModeOff = !active; mOverrideNightModeOn = active; - mOverrideNightModeUser = user; - persistNightModeOverrides(user); + mOverrideNightModeUser = mCurrentUser; + persistNightModeOverrides(mCurrentUser); } else if (mNightMode == UiModeManager.MODE_NIGHT_NO && active) { mNightMode = UiModeManager.MODE_NIGHT_YES; @@ -746,7 +762,7 @@ final class UiModeManagerService extends SystemService { } updateConfigurationLocked(); applyConfigurationExternallyLocked(); - persistNightMode(user); + persistNightMode(mCurrentUser); return true; } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 2fef82d352dd..045c51a516f4 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -1068,18 +1068,18 @@ public class VibratorService extends IVibratorService.Stub return attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY); } - private int getAppOpMode(Vibration vib) { + private int getAppOpMode(int uid, String packageName, VibrationAttributes attrs) { int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, - vib.attrs.getAudioAttributes().getUsage(), vib.uid, vib.opPkg); + attrs.getAudioAttributes().getUsage(), uid, packageName); if (mode == AppOpsManager.MODE_ALLOWED) { - mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); + mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, uid, packageName); } - if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(vib.attrs)) { + if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(attrs)) { // If we're just ignoring the vibration op then this is set by DND and we should ignore // if we're asked to bypass. AppOps won't be able to record this operation, so make // sure we at least note it in the logs for debugging. - Slog.d(TAG, "Bypassing DND for vibration: " + vib); + Slog.d(TAG, "Bypassing DND for vibrate from uid " + uid); mode = AppOpsManager.MODE_ALLOWED; } return mode; @@ -1101,7 +1101,7 @@ public class VibratorService extends IVibratorService.Stub return false; } - final int mode = getAppOpMode(vib); + final int mode = getAppOpMode(vib.uid, vib.opPkg, vib.attrs); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { // We might be getting calls from within system_server, so we don't actually @@ -1871,7 +1871,7 @@ public class VibratorService extends IVibratorService.Stub return SCALE_MUTE; } if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE, - vib.getUid(), -1 /*owningUid*/, true /*exported*/) + vib.getUid(), -1 /*owningUid*/, true /*exported*/) != PackageManager.PERMISSION_GRANTED) { Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid() + " tried to play externally controlled vibration" @@ -1879,6 +1879,14 @@ public class VibratorService extends IVibratorService.Stub return SCALE_MUTE; } + int mode = getAppOpMode(vib.getUid(), vib.getPackage(), vib.getVibrationAttributes()); + if (mode != AppOpsManager.MODE_ALLOWED) { + if (mode == AppOpsManager.MODE_ERRORED) { + Slog.w(TAG, "Would be an error: external vibrate from uid " + vib.getUid()); + } + return SCALE_MUTE; + } + final int scaleLevel; synchronized (mLock) { if (!vib.equals(mCurrentExternalVibration)) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 33a92e6ad0ac..3eb26de3a675 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1836,11 +1836,13 @@ public final class ActiveServices { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service + " type=" + resolvedType + " conn=" + connection.asBinder() + " flags=0x" + Integer.toHexString(flags)); + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); if (callerApp == null) { throw new SecurityException( "Unable to find app for caller " + caller - + " (pid=" + Binder.getCallingPid() + + " (pid=" + callingPid + ") when binding service " + service); } @@ -1880,19 +1882,19 @@ public final class ActiveServices { } if ((flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0 && !isCallerSystem) { - throw new SecurityException("Non-system caller (pid=" + Binder.getCallingPid() + throw new SecurityException("Non-system caller (pid=" + callingPid + ") set BIND_SCHEDULE_LIKE_TOP_APP when binding service " + service); } if ((flags & Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0 && !isCallerSystem) { throw new SecurityException( - "Non-system caller " + caller + " (pid=" + Binder.getCallingPid() + "Non-system caller " + caller + " (pid=" + callingPid + ") set BIND_ALLOW_WHITELIST_MANAGEMENT when binding service " + service); } if ((flags & Context.BIND_ALLOW_INSTANT) != 0 && !isCallerSystem) { throw new SecurityException( - "Non-system caller " + caller + " (pid=" + Binder.getCallingPid() + "Non-system caller " + caller + " (pid=" + callingPid + ") set BIND_ALLOW_INSTANT when binding service " + service); } @@ -1908,7 +1910,7 @@ public final class ActiveServices { ServiceLookupResult res = retrieveServiceLocked(service, instanceName, resolvedType, callingPackage, - Binder.getCallingPid(), Binder.getCallingUid(), userId, true, + callingPid, callingUid, userId, true, callerFg, isBindExternal, allowInstant); if (res == null) { return 0; @@ -2068,7 +2070,7 @@ public final class ActiveServices { if (!s.mAllowWhileInUsePermissionInFgs) { s.mAllowWhileInUsePermissionInFgs = shouldAllowWhileInUsePermissionInFgsLocked(callingPackage, - Binder.getCallingPid(), Binder.getCallingUid(), + callingPid, callingUid, service, s, false); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 91a1487c5245..71d12eed5412 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -176,6 +176,8 @@ import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; import android.app.WaitResult; +import android.app.backup.BackupManager; +import android.app.backup.BackupManager.OperationType; import android.app.backup.IBackupManager; import android.app.usage.UsageEvents; import android.app.usage.UsageEvents.Event; @@ -5374,7 +5376,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { thread.scheduleCreateBackupAgent(backupTarget.appInfo, compatibilityInfoForPackage(backupTarget.appInfo), - backupTarget.backupMode, backupTarget.userId); + backupTarget.backupMode, backupTarget.userId, backupTarget.operationType); } catch (Exception e) { Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e); badApp = true; @@ -13776,7 +13778,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Cause the target app to be launched if necessary and its backup agent // instantiated. The backup agent will invoke backupAgentCreated() on the // activity manager to announce its creation. - public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId) { + public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId, + @OperationType int operationType) { if (DEBUG_BACKUP) { Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode + " targetUserId=" + targetUserId + " callingUid = " + Binder.getCallingUid() @@ -13819,7 +13822,7 @@ public class ActivityManagerService extends IActivityManager.Stub + app.packageName + ": " + e); } - BackupRecord r = new BackupRecord(app, backupMode, targetUserId); + BackupRecord r = new BackupRecord(app, backupMode, targetUserId, operationType); ComponentName hostingName = (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL) ? new ComponentName(app.packageName, app.backupAgentName) @@ -13858,7 +13861,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc); try { proc.thread.scheduleCreateBackupAgent(app, - compatibilityInfoForPackage(app), backupMode, targetUserId); + compatibilityInfoForPackage(app), backupMode, targetUserId, + operationType); } catch (RemoteException e) { // Will time out on the backup manager side } diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java index 37b4be4ea0ec..d4198562c1dd 100644 --- a/services/core/java/com/android/server/am/BackupRecord.java +++ b/services/core/java/com/android/server/am/BackupRecord.java @@ -16,6 +16,8 @@ package com.android.server.am; +import android.app.backup.BackupManager; +import android.app.backup.BackupManager.OperationType; import android.content.pm.ApplicationInfo; /** @hide */ @@ -30,14 +32,16 @@ final class BackupRecord { final ApplicationInfo appInfo; // information about BackupAgent's app final int userId; // user for which backup is performed final int backupMode; // full backup / incremental / restore + @OperationType final int operationType; // see BackupManager#OperationType ProcessRecord app; // where this agent is running or null // ----- Implementation ----- - BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId) { + BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _operationType) { appInfo = _appInfo; backupMode = _backupMode; userId = _userId; + operationType = _operationType; } public String toString() { diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java index 0a30b763b8f4..d98298cbef5a 100644 --- a/services/core/java/com/android/server/backup/SystemBackupAgent.java +++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java @@ -20,6 +20,7 @@ import android.app.IWallpaperManager; import android.app.backup.BackupAgentHelper; import android.app.backup.BackupDataInput; import android.app.backup.BackupHelper; +import android.app.backup.BackupManager; import android.app.backup.FullBackup; import android.app.backup.FullBackupDataOutput; import android.app.backup.WallpaperBackupHelper; @@ -87,8 +88,8 @@ public class SystemBackupAgent extends BackupAgentHelper { private int mUserId = UserHandle.USER_SYSTEM; @Override - public void onCreate(UserHandle user) { - super.onCreate(user); + public void onCreate(UserHandle user, @BackupManager.OperationType int operationType) { + super.onCreate(user, operationType); mUserId = user.getIdentifier(); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1f85d1046523..1c93d4eb599b 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -48,6 +48,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.net.ConnectivityManager; +import android.net.DnsResolver; import android.net.INetworkManagementEventObserver; import android.net.Ikev2VpnProfile; import android.net.IpPrefix; @@ -79,6 +80,7 @@ import android.net.ipsec.ike.IkeSessionParams; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.FileUtils; import android.os.IBinder; import android.os.INetworkManagementService; @@ -123,6 +125,7 @@ import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.ArrayList; @@ -134,6 +137,8 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -190,6 +195,7 @@ public class Vpn { // automated reconnection private final Context mContext; + @VisibleForTesting final Dependencies mDeps; private final NetworkInfo mNetworkInfo; @VisibleForTesting protected String mPackage; private int mOwnerUID; @@ -252,17 +258,143 @@ public class Vpn { // Handle of the user initiating VPN. private final int mUserHandle; + interface RetryScheduler { + void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException; + } + + static class Dependencies { + public void startService(final String serviceName) { + SystemService.start(serviceName); + } + + public void stopService(final String serviceName) { + SystemService.stop(serviceName); + } + + public boolean isServiceRunning(final String serviceName) { + return SystemService.isRunning(serviceName); + } + + public boolean isServiceStopped(final String serviceName) { + return SystemService.isStopped(serviceName); + } + + public File getStateFile() { + return new File("/data/misc/vpn/state"); + } + + public void sendArgumentsToDaemon( + final String daemon, final LocalSocket socket, final String[] arguments, + final RetryScheduler retryScheduler) throws IOException, InterruptedException { + final LocalSocketAddress address = new LocalSocketAddress( + daemon, LocalSocketAddress.Namespace.RESERVED); + + // Wait for the socket to connect. + while (true) { + try { + socket.connect(address); + break; + } catch (Exception e) { + // ignore + } + retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); + } + socket.setSoTimeout(500); + + final OutputStream out = socket.getOutputStream(); + for (String argument : arguments) { + byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); + if (bytes.length >= 0xFFFF) { + throw new IllegalArgumentException("Argument is too large"); + } + out.write(bytes.length >> 8); + out.write(bytes.length); + out.write(bytes); + retryScheduler.checkInterruptAndDelay(false /* sleepLonger */); + } + out.write(0xFF); + out.write(0xFF); + + // Wait for End-of-File. + final InputStream in = socket.getInputStream(); + while (true) { + try { + if (in.read() == -1) { + break; + } + } catch (Exception e) { + // ignore + } + retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); + } + } + + @NonNull + public InetAddress resolve(final String endpoint) + throws ExecutionException, InterruptedException { + try { + return InetAddress.parseNumericAddress(endpoint); + } catch (IllegalArgumentException e) { + // Endpoint is not numeric : fall through and resolve + } + + final CancellationSignal cancellationSignal = new CancellationSignal(); + try { + final DnsResolver resolver = DnsResolver.getInstance(); + final CompletableFuture<InetAddress> result = new CompletableFuture(); + final DnsResolver.Callback<List<InetAddress>> cb = + new DnsResolver.Callback<List<InetAddress>>() { + @Override + public void onAnswer(@NonNull final List<InetAddress> answer, + final int rcode) { + if (answer.size() > 0) { + result.complete(answer.get(0)); + } else { + result.completeExceptionally( + new UnknownHostException(endpoint)); + } + } + + @Override + public void onError(@Nullable final DnsResolver.DnsException error) { + // Unfortunately UnknownHostException doesn't accept a cause, so + // print a message here instead. Only show the summary, not the + // full stack trace. + Log.e(TAG, "Async dns resolver error : " + error); + result.completeExceptionally(new UnknownHostException(endpoint)); + } + }; + resolver.query(null /* network, null for default */, endpoint, + DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb); + return result.get(); + } catch (final ExecutionException e) { + Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e); + throw e; + } catch (final InterruptedException e) { + Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e); + cancellationSignal.cancel(); + throw e; + } + } + + public boolean checkInterfacePresent(final Vpn vpn, final String iface) { + return vpn.jniCheck(iface) == 0; + } + } + public Vpn(Looper looper, Context context, INetworkManagementService netService, @UserIdInt int userHandle, @NonNull KeyStore keyStore) { - this(looper, context, netService, userHandle, keyStore, + this(looper, context, new Dependencies(), netService, userHandle, keyStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting - protected Vpn(Looper looper, Context context, INetworkManagementService netService, + protected Vpn(Looper looper, Context context, Dependencies deps, + INetworkManagementService netService, int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator) { mContext = context; + mDeps = deps; mNetd = netService; mUserHandle = userHandle; mLooper = looper; @@ -2129,7 +2261,8 @@ public class Vpn { } /** This class represents the common interface for all VPN runners. */ - private abstract class VpnRunner extends Thread { + @VisibleForTesting + abstract class VpnRunner extends Thread { protected VpnRunner(String name) { super(name); @@ -2638,7 +2771,7 @@ public class Vpn { } catch (InterruptedException e) { } for (String daemon : mDaemons) { - SystemService.stop(daemon); + mDeps.stopService(daemon); } } agentDisconnect(); @@ -2655,21 +2788,55 @@ public class Vpn { } } + private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) { + final String endpointAddressString = endpointAddress.getHostAddress(); + // Perform some safety checks before inserting the address in place. + // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd. + if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) { + throw new IllegalStateException("Unexpected daemons order"); + } + + // Respectively, the positions at which racoon and mtpd take the server address + // argument are 1 and 2. Not all types of VPN require both daemons however, and + // in that case the corresponding argument array is null. + if (mArguments[0] != null) { + if (!mProfile.server.equals(mArguments[0][1])) { + throw new IllegalStateException("Invalid server argument for racoon"); + } + mArguments[0][1] = endpointAddressString; + } + + if (mArguments[1] != null) { + if (!mProfile.server.equals(mArguments[1][2])) { + throw new IllegalStateException("Invalid server argument for mtpd"); + } + mArguments[1][2] = endpointAddressString; + } + } + private void bringup() { // Catch all exceptions so we can clean up a few things. try { + // resolve never returns null. If it does because of some bug, it will be + // caught by the catch() block below and cleanup gracefully. + final InetAddress endpointAddress = mDeps.resolve(mProfile.server); + + // Big hack : dynamically replace the address of the server in the arguments + // with the resolved address. + checkAndFixupArguments(endpointAddress); + // Initialize the timer. mBringupStartTime = SystemClock.elapsedRealtime(); // Wait for the daemons to stop. for (String daemon : mDaemons) { - while (!SystemService.isStopped(daemon)) { + while (!mDeps.isServiceStopped(daemon)) { checkInterruptAndDelay(true); } } // Clear the previous state. - File state = new File("/data/misc/vpn/state"); + final File state = mDeps.getStateFile(); state.delete(); if (state.exists()) { throw new IllegalStateException("Cannot delete the state"); @@ -2696,57 +2863,19 @@ public class Vpn { // Start the daemon. String daemon = mDaemons[i]; - SystemService.start(daemon); + mDeps.startService(daemon); // Wait for the daemon to start. - while (!SystemService.isRunning(daemon)) { + while (!mDeps.isServiceRunning(daemon)) { checkInterruptAndDelay(true); } // Create the control socket. mSockets[i] = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress( - daemon, LocalSocketAddress.Namespace.RESERVED); - - // Wait for the socket to connect. - while (true) { - try { - mSockets[i].connect(address); - break; - } catch (Exception e) { - // ignore - } - checkInterruptAndDelay(true); - } - mSockets[i].setSoTimeout(500); - - // Send over the arguments. - OutputStream out = mSockets[i].getOutputStream(); - for (String argument : arguments) { - byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); - if (bytes.length >= 0xFFFF) { - throw new IllegalArgumentException("Argument is too large"); - } - out.write(bytes.length >> 8); - out.write(bytes.length); - out.write(bytes); - checkInterruptAndDelay(false); - } - out.write(0xFF); - out.write(0xFF); - - // Wait for End-of-File. - InputStream in = mSockets[i].getInputStream(); - while (true) { - try { - if (in.read() == -1) { - break; - } - } catch (Exception e) { - // ignore - } - checkInterruptAndDelay(true); - } + + // Wait for the socket to connect and send over the arguments. + mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments, + this::checkInterruptAndDelay); } // Wait for the daemons to create the new state. @@ -2754,7 +2883,7 @@ public class Vpn { // Check if a running daemon is dead. for (int i = 0; i < mDaemons.length; ++i) { String daemon = mDaemons[i]; - if (mArguments[i] != null && !SystemService.isRunning(daemon)) { + if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) { throw new IllegalStateException(daemon + " is dead"); } } @@ -2764,7 +2893,8 @@ public class Vpn { // Now we are connected. Read and parse the new state. String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); if (parameters.length != 7) { - throw new IllegalStateException("Cannot parse the state"); + throw new IllegalStateException("Cannot parse the state: '" + + String.join("', '", parameters) + "'"); } // Set the interface and the addresses in the config. @@ -2793,20 +2923,15 @@ public class Vpn { } // Add a throw route for the VPN server endpoint, if one was specified. - String endpoint = parameters[5].isEmpty() ? mProfile.server : parameters[5]; - if (!endpoint.isEmpty()) { - try { - InetAddress addr = InetAddress.parseNumericAddress(endpoint); - if (addr instanceof Inet4Address) { - mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW)); - } else if (addr instanceof Inet6Address) { - mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW)); - } else { - Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint); - } - } catch (IllegalArgumentException e) { - Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e); - } + if (endpointAddress instanceof Inet4Address) { + mConfig.routes.add(new RouteInfo( + new IpPrefix(endpointAddress, 32), RTN_THROW)); + } else if (endpointAddress instanceof Inet6Address) { + mConfig.routes.add(new RouteInfo( + new IpPrefix(endpointAddress, 128), RTN_THROW)); + } else { + Log.e(TAG, "Unknown IP address family for VPN endpoint: " + + endpointAddress); } // Here is the last step and it must be done synchronously. @@ -2818,7 +2943,7 @@ public class Vpn { checkInterruptAndDelay(false); // Check if the interface is gone while we are waiting. - if (jniCheck(mConfig.interfaze) == 0) { + if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) { throw new IllegalStateException(mConfig.interfaze + " is gone"); } @@ -2849,7 +2974,7 @@ public class Vpn { while (true) { Thread.sleep(2000); for (int i = 0; i < mDaemons.length; i++) { - if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) { + if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) { return; } } diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 6f12155c5ec6..b8e579d58794 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -349,9 +349,7 @@ public abstract class BrightnessMappingStrategy { // Normalize entire brightness range to 0 - 1. protected static float normalizeAbsoluteBrightness(int brightness) { - return BrightnessSynchronizer.brightnessIntToFloat(brightness, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + return BrightnessSynchronizer.brightnessIntToFloat(brightness); } private Pair<float[], float[]> insertControlPoint( diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 0979ad67a8cd..397358b44362 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2550,8 +2550,7 @@ public final class DisplayManagerService extends SystemService { public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { synchronized (mSyncRoot) { - return mDisplayPowerController.requestPowerState(request, - waitForNegativeProximity); + return mDisplayPowerController.requestPowerState(request, waitForNegativeProximity); } } @@ -2679,6 +2678,10 @@ public final class DisplayManagerService extends SystemService { return getDisplayedContentSampleInternal(displayId, maxFrames, timestamp); } + @Override + public void ignoreProximitySensorUntilChanged() { + mDisplayPowerController.ignoreProximitySensorUntilChanged(); + } } class DesiredDisplayModeSpecsObserver diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 9411c5629457..58ef9d11ef97 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -117,6 +117,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int MSG_CONFIGURE_BRIGHTNESS = 5; private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 6; private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 7; + private static final int MSG_IGNORE_PROXIMITY = 8; private static final int PROXIMITY_UNKNOWN = -1; private static final int PROXIMITY_NEGATIVE = 0; @@ -263,6 +264,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // go to sleep by the user. While true, the screen remains off. private boolean mWaitingForNegativeProximity; + // True if the device should not take into account the proximity sensor + // until either the proximity sensor state changes, or there is no longer a + // request to listen to proximity sensor. + private boolean mIgnoreProximityUntilChanged; + // The actual proximity sensor threshold value. private float mProximityThreshold; @@ -699,13 +705,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Initialize screen state for battery stats. try { mBatteryStats.noteScreenState(mPowerState.getScreenState()); - mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt(mContext, + mBatteryStats.noteScreenBrightness(BrightnessSynchronizer.brightnessFloatToInt( mPowerState.getScreenBrightness())); } catch (RemoteException ex) { // same process } // Initialize all of the brightness tracking state - final float brightness = convertToNits(BrightnessSynchronizer.brightnessFloatToInt(mContext, + final float brightness = convertToNits(BrightnessSynchronizer.brightnessFloatToInt( mPowerState.getScreenBrightness())); if (brightness >= 0.0f) { mBrightnessTracker.start(brightness); @@ -760,8 +766,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mPowerRequest == null) { mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); - mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked; - mPendingWaitForNegativeProximityLocked = false; + updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mustInitialize = true; // Assume we're on and bright until told otherwise, since that's the state we turn @@ -770,8 +775,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } else if (mPendingRequestChangedLocked) { previousPolicy = mPowerRequest.policy; mPowerRequest.copyFrom(mPendingRequestLocked); - mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; - mPendingWaitForNegativeProximityLocked = false; + updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mDisplayReadyLocked = false; } else { @@ -822,9 +826,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Apply the proximity sensor. if (mProximitySensor != null) { if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) { + // At this point the policy says that the screen should be on, but we've been + // asked to listen to the prox sensor to adjust the display state, so lets make + // sure the sensor is on. setProximitySensorEnabled(true); if (!mScreenOffBecauseOfProximity - && mProximity == PROXIMITY_POSITIVE) { + && mProximity == PROXIMITY_POSITIVE + && !mIgnoreProximityUntilChanged) { + // Prox sensor already reporting "near" so we should turn off the screen. + // Also checked that we aren't currently set to ignore the proximity sensor + // temporarily. mScreenOffBecauseOfProximity = true; sendOnProximityPositiveWithWakelock(); } @@ -832,18 +843,28 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && mScreenOffBecauseOfProximity && mProximity == PROXIMITY_POSITIVE && state != Display.STATE_OFF) { + // The policy says that we should have the screen on, but it's off due to the prox + // and we've been asked to wait until the screen is far from the user to turn it + // back on. Let keep the prox sensor on so we can tell when it's far again. setProximitySensorEnabled(true); } else { + // We haven't been asked to use the prox sensor and we're not waiting on the screen + // to turn back on...so lets shut down the prox sensor. setProximitySensorEnabled(false); mWaitingForNegativeProximity = false; } + if (mScreenOffBecauseOfProximity - && mProximity != PROXIMITY_POSITIVE) { + && (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) { + // The screen *was* off due to prox being near, but now it's "far" so lets turn + // the screen back on. Also turn it back on if we've been asked to ignore the + // prox sensor temporarily. mScreenOffBecauseOfProximity = false; sendOnProximityNegativeWithWakelock(); } } else { mWaitingForNegativeProximity = false; + mIgnoreProximityUntilChanged = false; } if (mScreenOffBecauseOfProximity) { state = Display.STATE_OFF; @@ -1093,7 +1114,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call userInitiatedChange = false; } notifyBrightnessChanged( - BrightnessSynchronizer.brightnessFloatToInt(mContext, brightnessState), + BrightnessSynchronizer.brightnessFloatToInt(brightnessState), userInitiatedChange, hadUserBrightnessPoint); } @@ -1181,6 +1202,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call sendUpdatePowerState(); } + /** + * Ignores the proximity sensor until the sensor state changes, but only if the sensor is + * currently enabled and forcing the screen to be dark. + */ + public void ignoreProximitySensorUntilChanged() { + mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY); + } + public void setBrightnessConfiguration(BrightnessConfiguration c) { Message msg = mHandler.obtainMessage(MSG_CONFIGURE_BRIGHTNESS, c); msg.sendToTarget(); @@ -1341,8 +1370,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call try { // TODO(brightnessfloat): change BatteryStats to use float mBatteryStats.noteScreenBrightness( - BrightnessSynchronizer.brightnessFloatToInt( - mContext, target)); + BrightnessSynchronizer.brightnessFloatToInt(target)); } catch (RemoteException ex) { // same process } @@ -1529,6 +1557,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Register the listener. // Proximity sensor state already cleared initially. mProximitySensorEnabled = true; + mIgnoreProximityUntilChanged = false; mSensorManager.registerListener(mProximitySensorListener, mProximitySensor, SensorManager.SENSOR_DELAY_NORMAL, mHandler); } @@ -1538,6 +1567,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Clear the proximity sensor state for next time. mProximitySensorEnabled = false; mProximity = PROXIMITY_UNKNOWN; + mIgnoreProximityUntilChanged = false; mPendingProximity = PROXIMITY_UNKNOWN; mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); mSensorManager.unregisterListener(mProximitySensorListener); @@ -1580,6 +1610,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call && mPendingProximityDebounceTime >= 0) { final long now = SystemClock.uptimeMillis(); if (mPendingProximityDebounceTime <= now) { + if (mProximity != mPendingProximity) { + // if the status of the sensor changed, stop ignoring. + mIgnoreProximityUntilChanged = false; + Slog.i(TAG, "No longer ignoring proximity [" + mPendingProximity + "]"); + } // Sensor reading accepted. Apply the change then release the wake lock. mProximity = mPendingProximity; updatePowerState(); @@ -1723,6 +1758,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + private void updatePendingProximityRequestsLocked() { + mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; + mPendingWaitForNegativeProximityLocked = false; + + if (mIgnoreProximityUntilChanged) { + // Also, lets stop waiting for negative proximity if we're ignoring it. + mWaitingForNegativeProximity = false; + } + } + + private void ignoreProximitySensorUntilChangedInternal() { + if (!mIgnoreProximityUntilChanged + && mPowerRequest.useProximitySensor + && mProximity == PROXIMITY_POSITIVE) { + // Only ignore if it is still reporting positive (near) + mIgnoreProximityUntilChanged = true; + Slog.i(TAG, "Ignoring proximity"); + updatePowerState(); + } + } + private final Runnable mOnStateChangedRunnable = new Runnable() { @Override public void run() { @@ -1961,6 +2017,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mTemporaryAutoBrightnessAdjustment = Float.intBitsToFloat(msg.arg1); updatePowerState(); break; + + case MSG_IGNORE_PROXIMITY: + ignoreProximitySensorUntilChangedInternal(); + break; } } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 48fa1bf9f246..0be428bdba47 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -728,16 +728,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { try { if (isHalBrightnessRangeSpecified()) { brightness = displayBrightnessToHalBrightness( - BrightnessSynchronizer.brightnessFloatToIntRange( - getContext(), brightness)); + BrightnessSynchronizer.brightnessFloatToIntRange(brightness)); } if (mBacklight != null) { mBacklight.setBrightness(brightness); } Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenBrightness", - BrightnessSynchronizer.brightnessFloatToInt( - getContext(), brightness)); + BrightnessSynchronizer.brightnessFloatToInt(brightness)); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 596c1eccfabe..d675b81629a4 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -232,11 +232,12 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { mAutoTvOff = enabled; } + @Override @ServiceThreadOnly @VisibleForTesting void setIsActiveSource(boolean on) { assertRunOnServiceThread(); - mIsActiveSource = on; + super.setIsActiveSource(on); if (on) { getWakeLock().acquire(); } else { @@ -274,19 +275,15 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { @Override @ServiceThreadOnly - protected boolean handleActiveSource(HdmiCecMessage message) { - super.handleActiveSource(message); - if (mIsActiveSource) { - return true; - } + protected void onActiveSourceLost() { + assertRunOnServiceThread(); switch (mPowerStateChangeOnActiveSourceLost) { case STANDBY_NOW: mService.standby(); - return true; + return; case NONE: - return true; + return; } - return true; } @ServiceThreadOnly @@ -398,9 +395,12 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { } @Override + @ServiceThreadOnly protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) { + assertRunOnServiceThread(); if (physicalAddress != mService.getPhysicalAddress()) { - return; // Do nothing. + setActiveSource(physicalAddress); + return; } switch (mPlaybackDeviceActionOnRoutingControl) { case WAKE_UP_AND_SEND_ACTIVE_SOURCE: diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java index 1c677184b9d2..44ad8eea65ca 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java @@ -114,6 +114,19 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { } @ServiceThreadOnly + protected void onActiveSourceLost() { + // Nothing to do. + } + + @ServiceThreadOnly + protected void setActiveSource(int physicalAddress) { + assertRunOnServiceThread(); + // Invalidate the internal active source record. This will also update mIsActiveSource. + ActiveSource activeSource = ActiveSource.of(Constants.ADDR_INVALID, physicalAddress); + setActiveSource(activeSource); + } + + @ServiceThreadOnly protected boolean handleActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); int logicalAddress = message.getSource(); @@ -148,6 +161,9 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { if (physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) { setAndBroadcastActiveSource(message, physicalAddress); } + if (physicalAddress != mService.getPhysicalAddress()) { + setActiveSource(physicalAddress); + } switchInputOnReceivingNewActivePath(physicalAddress); return true; } @@ -156,18 +172,21 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRoutingChange(HdmiCecMessage message) { assertRunOnServiceThread(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams(), 2); + if (physicalAddress != mService.getPhysicalAddress()) { + setActiveSource(physicalAddress); + } if (!isRoutingControlFeatureEnabled()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); return true; } - int newPath = HdmiUtils.twoBytesToInt(message.getParams(), 2); // if the current device is a pure playback device if (!mIsSwitchDevice - && newPath == mService.getPhysicalAddress() + && physicalAddress == mService.getPhysicalAddress() && mService.isPlaybackDevice()) { - setAndBroadcastActiveSource(message, newPath); + setAndBroadcastActiveSource(message, physicalAddress); } - handleRoutingChangeAndInformation(newPath, message); + handleRoutingChangeAndInformation(physicalAddress, message); return true; } @@ -175,11 +194,14 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRoutingInformation(HdmiCecMessage message) { assertRunOnServiceThread(); + int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); + if (physicalAddress != mService.getPhysicalAddress()) { + setActiveSource(physicalAddress); + } if (!isRoutingControlFeatureEnabled()) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); return true; } - int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); // if the current device is a pure playback device if (!mIsSwitchDevice && physicalAddress == mService.getPhysicalAddress() @@ -222,7 +244,11 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice { @ServiceThreadOnly void setIsActiveSource(boolean on) { assertRunOnServiceThread(); + boolean wasActiveSource = mIsActiveSource; mIsActiveSource = on; + if (wasActiveSource && !mIsActiveSource) { + onActiveSourceLost(); + } } protected void wakeUpIfActiveSource() { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 5a4237938086..813def409c28 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -63,6 +63,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; +import android.os.VibrationEffect; import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -141,6 +142,8 @@ public class InputManagerService extends IInputManager.Stub private static final int MSG_RELOAD_DEVICE_ALIASES = 5; private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6; + private static final int DEFAULT_VIBRATION_MAGNITUDE = 192; + // Pointer to native input manager service object. private final long mPtr; @@ -1728,7 +1731,37 @@ public class InputManagerService extends IInputManager.Stub // Binder call @Override - public void vibrate(int deviceId, long[] pattern, int[] amplitudes, int repeat, IBinder token) { + public void vibrate(int deviceId, VibrationEffect effect, IBinder token) { + long[] pattern; + int[] amplitudes; + int repeat; + if (effect instanceof VibrationEffect.OneShot) { + VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) effect; + pattern = new long[] { 0, oneShot.getDuration() }; + int amplitude = oneShot.getAmplitude(); + // android framework uses DEFAULT_AMPLITUDE to signal that the vibration + // should use some built-in default value, denoted here as DEFAULT_VIBRATION_MAGNITUDE + if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) { + amplitude = DEFAULT_VIBRATION_MAGNITUDE; + } + amplitudes = new int[] { 0, amplitude }; + repeat = -1; + } else if (effect instanceof VibrationEffect.Waveform) { + VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; + pattern = waveform.getTimings(); + amplitudes = waveform.getAmplitudes(); + for (int i = 0; i < amplitudes.length; i++) { + if (amplitudes[i] == VibrationEffect.DEFAULT_AMPLITUDE) { + amplitudes[i] = DEFAULT_VIBRATION_MAGNITUDE; + } + } + repeat = waveform.getRepeatIndex(); + } else { + // TODO: Add support for prebaked effects + Log.w(TAG, "Pre-baked effects aren't supported on input devices"); + return; + } + if (repeat >= pattern.length) { throw new ArrayIndexOutOfBoundsException(); } @@ -1747,7 +1780,6 @@ public class InputManagerService extends IInputManager.Stub mVibratorTokens.put(token, v); } } - synchronized (v) { v.mVibrating = true; nativeVibrate(mPtr, deviceId, pattern, amplitudes, repeat, v.mTokenValue); diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java index c4f8441a995b..ac9b7ea0d808 100644 --- a/services/core/java/com/android/server/lights/LightsService.java +++ b/services/core/java/com/android/server/lights/LightsService.java @@ -318,8 +318,7 @@ public class LightsService extends SystemService { SurfaceControl.setDisplayBrightness(mDisplayToken, brightness); } else { // Old system - int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt( - getContext(), brightness); + int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(brightness); int color = brightnessInt & 0x000000ff; color = 0xff000000 | (color << 16) | (color << 8) | color; setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); diff --git a/services/core/java/com/android/server/media/HandlerExecutor.java b/services/core/java/com/android/server/media/HandlerExecutor.java new file mode 100644 index 000000000000..7c9e72bcf384 --- /dev/null +++ b/services/core/java/com/android/server/media/HandlerExecutor.java @@ -0,0 +1,45 @@ +/* + * Copyright 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.media; + +import android.annotation.NonNull; +import android.os.Handler; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + * An adapter {@link Executor} that posts all executed tasks onto the given + * {@link Handler}. + * + * @hide + */ +public class HandlerExecutor implements Executor { + private final Handler mHandler; + + public HandlerExecutor(@NonNull Handler handler) { + mHandler = Objects.requireNonNull(handler); + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 5d1b74912546..162c388dadd1 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -20,7 +20,6 @@ import android.media.MediaController2; import android.media.Session2CommandGroup; import android.media.Session2Token; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.ResultReceiver; import android.os.UserHandle; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d71c33e6e6f5..2d052da22714 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7288,12 +7288,12 @@ public class NotificationManagerService extends SystemService { @GuardedBy("mToastQueue") private void keepProcessAliveForToastIfNeededLocked(int pid) { - int toastCount = 0; // toasts from this pid + int toastCount = 0; // toasts from this pid, rendered by the app ArrayList<ToastRecord> list = mToastQueue; int n = list.size(); for (int i = 0; i < n; i++) { ToastRecord r = list.get(i); - if (r.pid == pid) { + if (r.pid == pid && r.keepProcessAlive()) { toastCount++; } } diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java index 2b91a00f9da5..17e0b39ea890 100644 --- a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java +++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java @@ -71,6 +71,13 @@ public class CustomToastRecord extends ToastRecord { } @Override + public boolean keepProcessAlive() { + // As custom toasts are rendered by the app, we need to keep the app alive for it to show + // the toast. + return true; + } + + @Override public String toString() { return "CustomToastRecord{" + Integer.toHexString(System.identityHashCode(this)) diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java index 7915f7013227..33906ccd3cd1 100644 --- a/services/core/java/com/android/server/notification/toast/ToastRecord.java +++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java @@ -85,4 +85,14 @@ public abstract class ToastRecord { } pw.println(prefix + this); } + + /** + * Returns whether it's necessary to bump the process state to keep it alive in order to show + * the toast. + */ + public boolean keepProcessAlive() { + // By default we assume the toast is rendered by the systemUI. Any toast rendered by the app + // should override this method. + return false; + } } diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 92c0c6af17d4..def9c78f98c7 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -35,6 +35,9 @@ import android.content.pm.parsing.component.ParsedInstrumentation; import android.content.pm.parsing.component.ParsedIntentInfo; import android.content.pm.parsing.component.ParsedMainComponent; import android.content.pm.parsing.component.ParsedProvider; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.HandlerThread; import android.os.Process; import android.os.Trace; import android.os.UserHandle; @@ -48,6 +51,7 @@ import android.util.SparseBooleanArray; import android.util.SparseSetArray; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; @@ -61,6 +65,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; import java.util.StringTokenizer; +import java.util.concurrent.Executor; /** * The entity responsible for filtering visibility between apps based on declarations in their @@ -96,6 +101,12 @@ public class AppsFilter { private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>(); /** + * Executor for running reasonably short background tasks such as building the initial + * visibility cache. + */ + private final Executor mBackgroundExecutor; + + /** * Pending full recompute of mQueriesViaComponent. Occurs when a package adds a new set of * protected broadcast. This in turn invalidates all prior additions and require a very * computationally expensive recomputing. @@ -125,6 +136,8 @@ public class AppsFilter { private PackageParser.SigningDetails mSystemSigningDetails; private Set<String> mProtectedBroadcasts = new ArraySet<>(); + private final Object mCacheLock = new Object(); + /** * This structure maps uid -> uid and indicates whether access from the first should be * filtered to the second. It's essentially a cache of the @@ -132,6 +145,7 @@ public class AppsFilter { * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on * initial scam and is null until {@link #onSystemReady()} is called. */ + @GuardedBy("mCacheLock") private volatile SparseArray<SparseBooleanArray> mShouldFilterCache; @VisibleForTesting(visibility = PRIVATE) @@ -139,13 +153,15 @@ public class AppsFilter { FeatureConfig featureConfig, String[] forceQueryableList, boolean systemAppsQueryable, - @Nullable OverlayReferenceMapper.Provider overlayProvider) { + @Nullable OverlayReferenceMapper.Provider overlayProvider, + Executor backgroundExecutor) { mFeatureConfig = featureConfig; mForceQueryableByDevicePackageNames = forceQueryableList; mSystemAppsQueryable = systemAppsQueryable; mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, overlayProvider); mStateProvider = stateProvider; + mBackgroundExecutor = backgroundExecutor; } /** @@ -337,8 +353,13 @@ public class AppsFilter { injector.getUserManagerInternal().getUserInfos()); } }; + HandlerThread appsFilterThread = new HandlerThread("appsFilter"); + appsFilterThread.start(); + Handler appsFilterHandler = new Handler(appsFilterThread.getLooper()); + Executor executor = new HandlerExecutor(appsFilterHandler); + AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, - forcedQueryablePackageNames, forceSystemAppsQueryable, null); + forcedQueryablePackageNames, forceSystemAppsQueryable, null, executor); featureConfig.setAppsFilter(appsFilter); return appsFilter; } @@ -470,29 +491,26 @@ public class AppsFilter { if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); } - if (mShouldFilterCache != null) { - // update the cache in a one-off manner since we've got all the information we need. - SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); - if (visibleUids == null) { - visibleUids = new SparseBooleanArray(); - mShouldFilterCache.put(recipientUid, visibleUids); + synchronized (mCacheLock) { + if (mShouldFilterCache != null) { + // update the cache in a one-off manner since we've got all the information we + // need. + SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); + if (visibleUids == null) { + visibleUids = new SparseBooleanArray(); + mShouldFilterCache.put(recipientUid, visibleUids); + } + visibleUids.put(visibleUid, false); } - visibleUids.put(visibleUid, false); } } } public void onSystemReady() { - mStateProvider.runWithState(new StateProvider.CurrentStateCallback() { - @Override - public void currentState(ArrayMap<String, PackageSetting> settings, - UserInfo[] users) { - mShouldFilterCache = new SparseArray<>(users.length * settings.size()); - } - }); - mFeatureConfig.onSystemReady(); mOverlayReferenceMapper.rebuildIfDeferred(); - updateEntireShouldFilterCache(); + mFeatureConfig.onSystemReady(); + + updateEntireShouldFilterCacheAsync(); } /** @@ -510,10 +528,12 @@ public class AppsFilter { } mStateProvider.runWithState((settings, users) -> { addPackageInternal(newPkgSetting, settings); - if (mShouldFilterCache != null) { - updateShouldFilterCacheForPackage( - null, newPkgSetting, settings, users, settings.size()); - } // else, rebuild entire cache when system is ready + synchronized (mCacheLock) { + if (mShouldFilterCache != null) { + updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting, + settings, users, settings.size()); + } // else, rebuild entire cache when system is ready + } }); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -607,6 +627,7 @@ public class AppsFilter { mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); } + @GuardedBy("mCacheLock") private void removeAppIdFromVisibilityCache(int appId) { if (mShouldFilterCache == null) { return; @@ -625,33 +646,47 @@ public class AppsFilter { } } + private void updateEntireShouldFilterCacheAsync() { + mBackgroundExecutor.execute(this::updateEntireShouldFilterCache); + } + private void updateEntireShouldFilterCache() { mStateProvider.runWithState((settings, users) -> { - mShouldFilterCache.clear(); + SparseArray<SparseBooleanArray> cache = + new SparseArray<>(users.length * settings.size()); for (int i = settings.size() - 1; i >= 0; i--) { - updateShouldFilterCacheForPackage( + updateShouldFilterCacheForPackage(cache, null /*skipPackage*/, settings.valueAt(i), settings, users, i); } + synchronized (mCacheLock) { + mShouldFilterCache = cache; + } }); } public void onUsersChanged() { - if (mShouldFilterCache != null) { - updateEntireShouldFilterCache(); + synchronized (mCacheLock) { + if (mShouldFilterCache != null) { + updateEntireShouldFilterCache(); + } } } private void updateShouldFilterCacheForPackage(String packageName) { - mStateProvider.runWithState((settings, users) -> { - updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName), - settings, users, settings.size() /*maxIndex*/); - }); - + synchronized (mCacheLock) { + if (mShouldFilterCache != null) { + mStateProvider.runWithState((settings, users) -> { + updateShouldFilterCacheForPackage(mShouldFilterCache, null /* skipPackage */, + settings.get(packageName), settings, users, + settings.size() /*maxIndex*/); + }); + } + } } - private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName, - PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings, - UserInfo[] allUsers, int maxIndex) { + private void updateShouldFilterCacheForPackage(SparseArray<SparseBooleanArray> cache, + @Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String, + PackageSetting> allSettings, UserInfo[] allUsers, int maxIndex) { for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { PackageSetting otherSetting = allSettings.valueAt(i); if (subjectSetting.appId == otherSetting.appId) { @@ -668,17 +703,17 @@ public class AppsFilter { for (int ou = 0; ou < userCount; ou++) { int otherUser = allUsers[ou].id; int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); - if (!mShouldFilterCache.contains(subjectUid)) { - mShouldFilterCache.put(subjectUid, new SparseBooleanArray(appxUidCount)); + if (!cache.contains(subjectUid)) { + cache.put(subjectUid, new SparseBooleanArray(appxUidCount)); } int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); - if (!mShouldFilterCache.contains(otherUid)) { - mShouldFilterCache.put(otherUid, new SparseBooleanArray(appxUidCount)); + if (!cache.contains(otherUid)) { + cache.put(otherUid, new SparseBooleanArray(appxUidCount)); } - mShouldFilterCache.get(subjectUid).put(otherUid, + cache.get(subjectUid).put(otherUid, shouldFilterApplicationInternal( subjectUid, subjectSetting, otherSetting, otherUser)); - mShouldFilterCache.get(otherUid).put(subjectUid, + cache.get(otherUid).put(subjectUid, shouldFilterApplicationInternal( otherUid, otherSetting, subjectSetting, subjectUser)); } @@ -712,7 +747,8 @@ public class AppsFilter { * This method recomputes all component / intent-based visibility and is intended to match the * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)} */ - private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings) { + private void recomputeComponentVisibility( + ArrayMap<String, PackageSetting> existingSettings) { mQueriesViaComponent.clear(); for (int i = existingSettings.size() - 1; i >= 0; i--) { PackageSetting setting = existingSettings.valueAt(i); @@ -854,15 +890,17 @@ public class AppsFilter { } } - removeAppIdFromVisibilityCache(setting.appId); - if (mShouldFilterCache != null && setting.sharedUser != null) { - for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { - PackageSetting siblingSetting = setting.sharedUser.packages.valueAt(i); - if (siblingSetting == setting) { - continue; + synchronized (mCacheLock) { + removeAppIdFromVisibilityCache(setting.appId); + if (mShouldFilterCache != null && setting.sharedUser != null) { + for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { + PackageSetting siblingSetting = setting.sharedUser.packages.valueAt(i); + if (siblingSetting == setting) { + continue; + } + updateShouldFilterCacheForPackage(mShouldFilterCache, setting.name, + siblingSetting, settings, users, settings.size()); } - updateShouldFilterCacheForPackage( - setting.name, siblingSetting, settings, users, settings.size()); } } }); @@ -888,26 +926,29 @@ public class AppsFilter { || callingAppId == targetPkgSetting.appId) { return false; } - if (mShouldFilterCache != null) { // use cache - SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); - final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); - if (shouldFilterTargets == null) { - Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid); - return true; - } - int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); - if (indexOfTargetUid < 0) { - Slog.w(TAG, "Encountered calling -> target with no cached rules: " - + callingUid + " -> " + targetUid); - return true; - } - if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { - return false; - } - } else { - if (!shouldFilterApplicationInternal( - callingUid, callingSetting, targetPkgSetting, userId)) { - return false; + synchronized (mCacheLock) { + if (mShouldFilterCache != null) { // use cache + SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); + final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); + if (shouldFilterTargets == null) { + Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + + callingUid); + return true; + } + int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); + if (indexOfTargetUid < 0) { + Slog.w(TAG, "Encountered calling -> target with no cached rules: " + + callingUid + " -> " + targetUid); + return true; + } + if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { + return false; + } + } else { + if (!shouldFilterApplicationInternal( + callingUid, callingSetting, targetPkgSetting, userId)) { + return false; + } } } if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(callingAppId)) { diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 0eaac4140c14..9646b9ce8edf 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -52,6 +52,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; import com.android.server.pm.parsing.PackageInfoUtils; import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.permission.PermissionManagerServiceInternal; import libcore.io.IoUtils; import libcore.util.HexEncoding; @@ -112,6 +113,7 @@ class InstantAppRegistry { private static final String ATTR_GRANTED = "granted"; private final PackageManagerService mService; + private final PermissionManagerServiceInternal mPermissionManager; private final CookiePersistence mCookiePersistence; /** State for uninstalled instant apps */ @@ -131,8 +133,10 @@ class InstantAppRegistry { @GuardedBy("mService.mLock") private SparseArray<SparseBooleanArray> mInstalledInstantAppUids; - public InstantAppRegistry(PackageManagerService service) { + public InstantAppRegistry(PackageManagerService service, + PermissionManagerServiceInternal permissionManager) { mService = service; + mPermissionManager = permissionManager; mCookiePersistence = new CookiePersistence(BackgroundThread.getHandler().getLooper()); } @@ -861,7 +865,8 @@ class InstantAppRegistry { String[] requestedPermissions = new String[pkg.getRequestedPermissions().size()]; pkg.getRequestedPermissions().toArray(requestedPermissions); - Set<String> permissions = ps.getPermissionsState().getPermissions(userId); + Set<String> permissions = mPermissionManager.getGrantedPermissions( + pkg.getPackageName(), userId); String[] grantedPermissions = new String[permissions.size()]; permissions.toArray(grantedPermissions); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 55e7ca8ca838..840645edcb82 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -442,7 +442,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // After reboot housekeeping. for (int i = 0; i < mSessions.size(); ++i) { PackageInstallerSession session = mSessions.valueAt(i); - session.onAfterSessionRead(); + session.onAfterSessionRead(mSessions); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 05026a0cafb6..ff9edd511e84 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -122,7 +122,7 @@ import android.util.ArraySet; import android.util.ExceptionUtils; import android.util.MathUtils; import android.util.Slog; -import android.util.SparseIntArray; +import android.util.SparseArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.R; @@ -336,7 +336,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private PackageParser.SigningDetails mSigningDetails; @GuardedBy("mLock") - private SparseIntArray mChildSessionIds = new SparseIntArray(); + private SparseArray<PackageInstallerSession> mChildSessions = new SparseArray<>(); @GuardedBy("mLock") private int mParentSessionId; @@ -589,7 +589,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.mShouldBeSealed = sealed; if (childSessionIds != null) { for (int childSessionId : childSessionIds) { - mChildSessionIds.put(childSessionId, 0); + // Null values will be resolved to actual object references in + // #onAfterSessionRead later. + mChildSessions.put(childSessionId, null); } } this.mParentSessionId = parentSessionId; @@ -708,10 +710,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.isStaged = params.isStaged; info.rollbackDataPolicy = params.rollbackDataPolicy; info.parentSessionId = mParentSessionId; - info.childSessionIds = mChildSessionIds.copyKeys(); - if (info.childSessionIds == null) { - info.childSessionIds = EMPTY_CHILD_SESSION_ARRAY; - } + info.childSessionIds = getChildSessionIdsLocked(); info.isStagedSessionApplied = mStagedSessionApplied; info.isStagedSessionReady = mStagedSessionReady; info.isStagedSessionFailed = mStagedSessionFailed; @@ -1159,27 +1158,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } if (isMultiPackage()) { - final SparseIntArray remainingSessions; - final int[] childSessionIds; synchronized (mLock) { - remainingSessions = mChildSessionIds.clone(); - childSessionIds = mChildSessionIds.copyKeys(); - } - final IntentSender childIntentSender = - new ChildStatusIntentReceiver(remainingSessions, statusReceiver) - .getIntentSender(); - boolean sealFailed = false; - for (int i = childSessionIds.length - 1; i >= 0; --i) { - final int childSessionId = childSessionIds[i]; - // seal all children, regardless if any of them fail; we'll throw/return - // as appropriate once all children have been processed - if (!mSessionProvider.getSession(childSessionId) - .markAsSealed(childIntentSender, forTransfer)) { - sealFailed = true; + final IntentSender childIntentSender = + new ChildStatusIntentReceiver(mChildSessions.clone(), statusReceiver) + .getIntentSender(); + boolean sealFailed = false; + for (int i = mChildSessions.size() - 1; i >= 0; --i) { + // seal all children, regardless if any of them fail; we'll throw/return + // as appropriate once all children have been processed + if (!mChildSessions.valueAt(i) + .markAsSealed(childIntentSender, forTransfer)) { + sealFailed = true; + } + } + if (sealFailed) { + return; } - } - if (sealFailed) { - return; } } @@ -1218,21 +1212,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } if (isMultiPackage()) { - final int[] childSessionIds; + final List<PackageInstallerSession> childSessions; synchronized (mLock) { - childSessionIds = mChildSessionIds.copyKeys(); + childSessions = getChildSessionsLocked(); } - int childCount = childSessionIds.length; + int childCount = childSessions.size(); // This will contain all child sessions that do not encounter an unrecoverable failure ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount); for (int i = childCount - 1; i >= 0; --i) { - final int childSessionId = childSessionIds[i]; // commit all children, regardless if any of them fail; we'll throw/return // as appropriate once all children have been processed try { - PackageInstallerSession session = mSessionProvider.getSession(childSessionId); + PackageInstallerSession session = childSessions.get(i); allSessionsReady &= session.streamValidateAndCommit(); nonFailingSessions.add(session); } catch (PackageManagerException e) { @@ -1293,7 +1286,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private class ChildStatusIntentReceiver { - private final SparseIntArray mChildSessionsRemaining; + private final SparseArray<PackageInstallerSession> mChildSessionsRemaining; private final IntentSender mStatusReceiver; private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override @@ -1303,7 +1296,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } }; - private ChildStatusIntentReceiver(SparseIntArray remainingSessions, + private ChildStatusIntentReceiver(SparseArray<PackageInstallerSession> remainingSessions, IntentSender statusReceiver) { this.mChildSessionsRemaining = remainingSessions; this.mStatusReceiver = statusReceiver; @@ -1413,8 +1406,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) { Objects.requireNonNull(statusReceiver); - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); - synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotDestroyedLocked("commit"); @@ -1446,7 +1437,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } try { - sealLocked(childSessions); + sealLocked(); } catch (PackageManagerException e) { return false; } @@ -1487,21 +1478,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return true; } - /** Return a list of child sessions or null if the session is not multipackage - * - * <p> This method is handy to prevent potential deadlocks (b/123391593) - */ - private @Nullable List<PackageInstallerSession> getChildSessionsNotLocked() { - if (Thread.holdsLock(mLock)) { - Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() - + " is holding mLock", new Throwable()); - } + @GuardedBy("mLock") + private @Nullable List<PackageInstallerSession> getChildSessionsLocked() { List<PackageInstallerSession> childSessions = null; if (isMultiPackage()) { - final int[] childSessionIds = getChildSessionIds(); - childSessions = new ArrayList<>(childSessionIds.length); - for (int childSessionId : childSessionIds) { - childSessions.add(mSessionProvider.getSession(childSessionId)); + int size = mChildSessions.size(); + childSessions = new ArrayList<>(size); + for (int i = 0; i < size; ++i) { + childSessions.add(mChildSessions.valueAt(i)); } } return childSessions; @@ -1563,14 +1547,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * session was sealed this is the only possible exception. */ @GuardedBy("mLock") - private void sealLocked(List<PackageInstallerSession> childSessions) + private void sealLocked() throws PackageManagerException { try { assertNoWriteFileTransfersOpenLocked(); assertPreparedAndNotDestroyedLocked("sealing of session"); mSealed = true; - + List<PackageInstallerSession> childSessions = getChildSessionsLocked(); if (childSessions != null) { assertMultiPackageConsistencyLocked(childSessions); } @@ -1657,17 +1641,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * * <p> This is meant to be called after all of the sessions are loaded and added to * PackageInstallerService + * + * @param allSessions All sessions loaded by PackageInstallerService, guaranteed to be + * immutable by the caller during the method call. Used to resolve child + * sessions Ids to actual object reference. */ - void onAfterSessionRead() { + void onAfterSessionRead(SparseArray<PackageInstallerSession> allSessions) { synchronized (mLock) { + // Resolve null values to actual object references + for (int i = mChildSessions.size() - 1; i >= 0; --i) { + int childSessionId = mChildSessions.keyAt(i); + PackageInstallerSession childSession = allSessions.get(childSessionId); + if (childSession != null) { + mChildSessions.setValueAt(i, childSession); + } else { + Slog.e(TAG, "Child session not existed: " + childSessionId); + mChildSessions.removeAt(i); + } + } + if (!mShouldBeSealed || isStagedAndInTerminalState()) { return; } - } - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); - synchronized (mLock) { try { - sealLocked(childSessions); + sealLocked(); if (isApexInstallation()) { // APEX installations rely on certain fields to be populated after reboot. @@ -1708,14 +1705,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { throw new SecurityException("Can only transfer sessions that use public options"); } - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); - synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotSealedLocked("transfer"); try { - sealLocked(childSessions); + sealLocked(); } catch (PackageManagerException e) { throw new IllegalArgumentException("Package is not valid", e); } @@ -1746,14 +1741,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - // For a multiPackage session, read the child sessions - // outside of the lock, because reading the child - // sessions with the lock held could lead to deadlock - // (b/123391593). - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); - try { - verifyNonStaged(childSessions); + verifyNonStaged(); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); @@ -1762,7 +1751,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - private void verifyNonStaged(List<PackageInstallerSession> childSessions) + private void verifyNonStaged() throws PackageManagerException { final PackageManagerService.VerificationParams verifyingSession = makeVerificationParams(); @@ -1770,6 +1759,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } if (isMultiPackage()) { + final List<PackageInstallerSession> childSessions; + synchronized (mLock) { + childSessions = getChildSessionsLocked(); + } List<PackageManagerService.VerificationParams> verifyingChildSessions = new ArrayList<>(childSessions.size()); boolean success = true; @@ -1803,7 +1796,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - private void installNonStaged(List<PackageInstallerSession> childSessions) + private void installNonStaged() throws PackageManagerException { final PackageManagerService.InstallParams installingSession = makeInstallParams(); @@ -1811,6 +1804,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } if (isMultiPackage()) { + final List<PackageInstallerSession> childSessions; + synchronized (mLock) { + childSessions = getChildSessionsLocked(); + } List<PackageManagerService.InstallParams> installingChildSessions = new ArrayList<>(childSessions.size()); boolean success = true; @@ -2004,9 +2001,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); try { - installNonStaged(childSessions); + installNonStaged(); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); @@ -2741,15 +2737,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - /** - * Adds a child session ID without any safety / sanity checks. This should only be used to - * build a session from XML or similar. - */ - @GuardedBy("mLock") - void addChildSessionIdLocked(int sessionId) { - mChildSessionIds.put(sessionId, 0); - } - public void open() throws IOException { if (mActiveCount.getAndIncrement() == 0) { mCallback.onSessionActiveChanged(this, true); @@ -2804,7 +2791,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { + getParentSessionId() + " and may not be abandoned directly."); } - List<PackageInstallerSession> childSessions = getChildSessionsNotLocked(); synchronized (mLock) { if (params.isStaged && mDestroyed) { // If a user abandons staged session in an unsafe state, then system will try to @@ -2828,7 +2814,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mCallback.onStagedSessionChanged(this); return; } - cleanStageDir(childSessions); + cleanStageDir(getChildSessionsLocked()); } if (mRelinquished) { @@ -3149,8 +3135,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private int[] getChildSessionIdsLocked() { - final int[] childSessionIds = mChildSessionIds.copyKeys(); - return childSessionIds != null ? childSessionIds : EMPTY_CHILD_SESSION_ARRAY; + int size = mChildSessions.size(); + if (size == 0) { + return EMPTY_CHILD_SESSION_ARRAY; + } + final int[] childSessionIds = new int[size]; + for (int i = 0; i < size; ++i) { + childSessionIds[i] = mChildSessions.keyAt(i); + } + return childSessionIds; } @Override @@ -3205,12 +3198,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotSealedLocked("addChildSessionId"); - final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId); + final int indexOfSession = mChildSessions.indexOfKey(childSessionId); if (indexOfSession >= 0) { return; } childSession.setParentSessionId(this.sessionId); - addChildSessionIdLocked(childSessionId); + mChildSessions.put(childSessionId, childSession); } } finally { releaseTransactionLock(); @@ -3220,30 +3213,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void removeChildSessionId(int sessionId) { - final PackageInstallerSession session = mSessionProvider.getSession(sessionId); - try { - acquireTransactionLock(); - if (session != null) { - session.acquireTransactionLock(); - } - - synchronized (mLock) { - assertCallerIsOwnerOrRootLocked(); - assertPreparedAndNotSealedLocked("removeChildSessionId"); + synchronized (mLock) { + assertCallerIsOwnerOrRootLocked(); + assertPreparedAndNotSealedLocked("removeChildSessionId"); - final int indexOfSession = mChildSessionIds.indexOfKey(sessionId); - if (indexOfSession < 0) { - // not added in the first place; no-op - return; - } - if (session != null) { - session.setParentSessionId(SessionInfo.INVALID_ID); - } - mChildSessionIds.removeAt(indexOfSession); + final int indexOfSession = mChildSessions.indexOfKey(sessionId); + if (indexOfSession < 0) { + // not added in the first place; no-op + return; } - } finally { - releaseTransactionLock(); - if (session != null) { + PackageInstallerSession session = mChildSessions.valueAt(indexOfSession); + try { + acquireTransactionLock(); + session.acquireTransactionLock(); + session.setParentSessionId(SessionInfo.INVALID_ID); + mChildSessions.removeAt(indexOfSession); + } finally { + releaseTransactionLock(); session.releaseTransactionLock(); } } @@ -3334,6 +3320,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** {@hide} */ void setStagedSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) { + List<PackageInstallerSession> childSessions; synchronized (mLock) { // Do not allow destroyed/failed staged session to change state if (mDestroyed || mStagedSessionFailed) return; @@ -3343,13 +3330,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mStagedSessionErrorCode = errorCode; mStagedSessionErrorMessage = errorMessage; Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage); + childSessions = getChildSessionsLocked(); } - cleanStageDirNotLocked(); + cleanStageDir(childSessions); mCallback.onStagedSessionChanged(this); } /** {@hide} */ void setStagedSessionApplied() { + List<PackageInstallerSession> childSessions; synchronized (mLock) { // Do not allow destroyed/failed staged session to change state if (mDestroyed || mStagedSessionFailed) return; @@ -3359,8 +3348,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mStagedSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; mStagedSessionErrorMessage = ""; Slog.d(TAG, "Marking session " + sessionId + " as applied"); + childSessions = getChildSessionsLocked(); } - cleanStageDirNotLocked(); + cleanStageDir(childSessions); mCallback.onStagedSessionChanged(this); } @@ -3428,23 +3418,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - /** - * <b>must not hold {@link #mLock}</b> - */ - private void cleanStageDirNotLocked() { - if (Thread.holdsLock(mLock)) { - Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() - + " is holding mLock", new Throwable()); - } - cleanStageDir(getChildSessionsNotLocked()); - } - private void cleanStageDir(List<PackageInstallerSession> childSessions) { if (childSessions != null) { for (PackageInstallerSession childSession : childSessions) { - if (childSession != null) { - childSession.cleanStageDir(); - } + childSession.cleanStageDir(); } } else { cleanStageDir(); @@ -3504,7 +3481,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("params.isMultiPackage", params.isMultiPackage); pw.printPair("params.isStaged", params.isStaged); pw.printPair("mParentSessionId", mParentSessionId); - pw.printPair("mChildSessionIds", mChildSessionIds); + pw.printPair("mChildSessionIds", getChildSessionIdsLocked()); pw.printPair("mStagedSessionApplied", mStagedSessionApplied); pw.printPair("mStagedSessionFailed", mStagedSessionFailed); pw.printPair("mStagedSessionReady", mStagedSessionReady); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 58a1648e51ad..a874f612e106 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2970,7 +2970,7 @@ public class PackageManagerService extends IPackageManager.Stub mHandler = new PackageHandler(mHandlerThread.getLooper()); mProcessLoggingHandler = new ProcessLoggingHandler(); Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); - mInstantAppRegistry = new InstantAppRegistry(this); + mInstantAppRegistry = new InstantAppRegistry(this, mPermissionManager); ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig = systemConfig.getSharedLibraries(); @@ -4385,14 +4385,13 @@ public class PackageManagerService extends IPackageManager.Stub final PackageUserState state = ps.readUserState(userId); AndroidPackage p = ps.pkg; if (p != null) { - final PermissionsState permissionsState = ps.getPermissionsState(); - // Compute GIDs only if requested final int[] gids = (flags & PackageManager.GET_GIDS) == 0 - ? EMPTY_INT_ARRAY : permissionsState.computeGids(userId); + ? EMPTY_INT_ARRAY : mPermissionManager.getPackageGids(ps.name, userId); // Compute granted permissions only if package has requested permissions final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions()) - ? Collections.emptySet() : permissionsState.getPermissions(userId); + ? Collections.emptySet() + : mPermissionManager.getGrantedPermissions(ps.name, userId); PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags, ps.firstInstallTime, ps.lastUpdateTime, permissions, state, userId, ps); @@ -4863,13 +4862,13 @@ public class PackageManagerService extends IPackageManager.Stub } // TODO: Shouldn't this be checking for package installed state for userId and // return null? - return ps.getPermissionsState().computeGids(userId); + return mPermissionManager.getPackageGids(packageName, userId); } if ((flags & MATCH_KNOWN_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null && ps.isMatch(flags) && !shouldFilterApplicationLocked(ps, callingUid, userId)) { - return ps.getPermissionsState().computeGids(userId); + return mPermissionManager.getPackageGids(packageName, userId); } } } @@ -10352,6 +10351,7 @@ public class PackageManagerService extends IPackageManager.Stub mInstaller.rmPackageDir(codePath.getAbsolutePath()); if (codePathParent.getName().startsWith(RANDOM_DIR_PREFIX)) { mInstaller.rmPackageDir(codePathParent.getAbsolutePath()); + removeCachedResult(codePathParent); } } catch (InstallerException e) { Slog.w(TAG, "Failed to remove code path", e); @@ -10361,6 +10361,16 @@ public class PackageManagerService extends IPackageManager.Stub } } + private void removeCachedResult(@NonNull File codePath) { + if (mCacheDir == null) { + return; + } + + final PackageCacher cacher = new PackageCacher(mCacheDir); + // Find and delete the cached result belong to the given codePath. + cacher.cleanCachedResult(codePath); + } + private int[] resolveUserIds(int userId) { return (userId == UserHandle.USER_ALL) ? mUserManager.getUserIds() : new int[] { userId }; } @@ -24948,9 +24958,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int[] getPermissionGids(String permissionName, int userId) { - synchronized (mLock) { - return getPermissionGidsLocked(permissionName, userId); - } + return mPermissionManager.getPermissionGids(permissionName, userId); } @Override @@ -25271,16 +25279,6 @@ public class PackageManagerService extends IPackageManager.Stub return null; } - @GuardedBy("mLock") - public int[] getPermissionGidsLocked(String permissionName, int userId) { - BasePermission perm - = mPermissionManager.getPermissionSettings().getPermission(permissionName); - if (perm != null) { - return perm.computeGids(userId); - } - return null; - } - @Override public int getRuntimePermissionsVersion(@UserIdInt int userId) { Preconditions.checkArgumentNonnegative(userId); @@ -25414,18 +25412,7 @@ public class PackageManagerService extends IPackageManager.Stub int mode = mInjector.getAppOpsManager().checkOpNoThrow( AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, Binder.getCallingUid(), packageName); - if (mode == MODE_ALLOWED) { - return false; - } else if (mode == MODE_IGNORED) { - return true; - } else { - synchronized (mLock) { - boolean manifestWhitelisted = - mPackages.get(packageName).getAutoRevokePermissions() - == ApplicationInfo.AUTO_REVOKE_DISALLOWED; - return manifestWhitelisted; - } - } + return mode == MODE_IGNORED; } @Override diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index e3bee7228c68..bf9506ad51f1 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -134,6 +134,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -4784,7 +4785,7 @@ public class UserManagerService extends IUserManager.Stub { } } } - pw.println(); + pw.println("Device properties:"); pw.println(" Device owner id:" + mDeviceOwnerUserId); pw.println(); @@ -4801,8 +4802,26 @@ public class UserManagerService extends IUserManager.Stub { } } synchronized (mUserStates) { - pw.println(" Started users state: " + mUserStates); + pw.print(" Started users state: ["); + final int size = mUserStates.states.size(); + for (int i = 0; i < size; i++) { + final int userId = mUserStates.states.keyAt(i); + final int state = mUserStates.states.valueAt(i); + pw.print(userId); + pw.print('='); + pw.print(UserState.stateToString(state)); + if (i != size - 1) pw.print(", "); + } + pw.println(']'); } + + synchronized (mUsersLock) { + pw.println(); + pw.print("Cached user IDs: "); + pw.println(Arrays.toString(mUserIds)); + pw.println(); + } + } // synchronized (mPackagesLock) // Dump some capabilities diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index be93b8f95b79..03771be0ce7c 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2454,6 +2454,36 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + @NonNull + private Set<String> getGrantedPermissions(@NonNull String packageName, + @UserIdInt int userId) { + final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName); + if (ps == null) { + return null; + } + final PermissionsState permissionsState = ps.getPermissionsState(); + return permissionsState.getPermissions(userId); + } + + @Nullable + private int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) { + BasePermission permission = mSettings.getPermission(permissionName); + if (permission == null) { + return null; + } + return permission.computeGids(userId); + } + + @Nullable + private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) { + final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName); + if (ps == null) { + return null; + } + final PermissionsState permissionsState = ps.getPermissionsState(); + return permissionsState.computeGids(userId); + } + /** * Restore the permission state for a package. * @@ -4650,6 +4680,22 @@ public class PermissionManagerService extends IPermissionManager.Stub { public void removeAllPermissions(AndroidPackage pkg, boolean chatty) { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } + @NonNull + @Override + public Set<String> getGrantedPermissions(@NonNull String packageName, + @UserIdInt int userId) { + return PermissionManagerService.this.getGrantedPermissions(packageName, userId); + } + @Nullable + @Override + public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) { + return PermissionManagerService.this.getPermissionGids(permissionName, userId); + } + @Nullable + @Override + public int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) { + return PermissionManagerService.this.getPackageGids(packageName, userId); + } @Override public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds, String[] grantedPermissions, int callingUid) { diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java index 2e83b23f57d8..cfa371ddbad3 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java @@ -28,6 +28,7 @@ import com.android.server.pm.parsing.pkg.AndroidPackage; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.function.Consumer; /** @@ -263,6 +264,25 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager public abstract void addAllPermissionGroups(@NonNull AndroidPackage pkg, boolean chatty); public abstract void removeAllPermissions(@NonNull AndroidPackage pkg, boolean chatty); + /** + * Get all the permissions granted to a package. + */ + @NonNull + public abstract Set<String> getGrantedPermissions(@NonNull String packageName, + @UserIdInt int userId); + + /** + * Get the GIDs of a permission. + */ + @Nullable + public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId); + + /** + * Get the GIDs computed from the permission state of a package. + */ + @Nullable + public abstract int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId); + /** Retrieve the packages that have requested the given app op permission */ public abstract @Nullable String[] getAppOpPermissionPackages( @NonNull String permName, int callingUid); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 03868e922bdd..fa3bcb6b98eb 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -933,6 +933,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event); + GestureLauncherService gestureService = LocalServices.getService( GestureLauncherService.class); boolean gesturedServiceIntercepted = false; @@ -952,7 +954,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // If the power key has still not yet been handled, then detect short // press, long press, or multi press and decide what to do. mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered - || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted; + || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted + || handledByPowerManager; if (!mPowerKeyHandled) { if (interactive) { // When interactive, we're already awake. diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index f9a49c9d8244..882ed1b7960b 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -86,6 +86,7 @@ import android.util.SparseArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; +import android.view.KeyEvent; import com.android.internal.BrightnessSynchronizer; import com.android.internal.annotations.VisibleForTesting; @@ -892,19 +893,13 @@ public final class PowerManagerService extends SystemService || def == INVALID_BRIGHTNESS_IN_CONFIG) { mScreenBrightnessMinimum = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessSettingMinimum), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessSettingMinimum)); mScreenBrightnessMaximum = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessSettingMaximum), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessSettingMaximum)); mScreenBrightnessDefault = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessSettingDefault), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessSettingDefault)); } else { mScreenBrightnessMinimum = min; mScreenBrightnessMaximum = max; @@ -913,18 +908,14 @@ public final class PowerManagerService extends SystemService if (doze == INVALID_BRIGHTNESS_IN_CONFIG) { mScreenBrightnessDoze = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessDoze), PowerManager.BRIGHTNESS_OFF + 1, - PowerManager.BRIGHTNESS_ON, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessDoze)); } else { mScreenBrightnessDoze = doze; } if (dim == INVALID_BRIGHTNESS_IN_CONFIG) { mScreenBrightnessDim = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessDim), PowerManager.BRIGHTNESS_OFF + 1, - PowerManager.BRIGHTNESS_ON, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessDim)); } else { mScreenBrightnessDim = dim; } @@ -939,19 +930,13 @@ public final class PowerManagerService extends SystemService || vrDef == INVALID_BRIGHTNESS_IN_CONFIG) { mScreenBrightnessMinimumVr = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessForVrSettingMinimum), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessForVrSettingMinimum)); mScreenBrightnessMaximumVr = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessForVrSettingMaximum), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessForVrSettingMaximum)); mScreenBrightnessDefaultVr = BrightnessSynchronizer.brightnessIntToFloat( mContext.getResources().getInteger(com.android.internal.R.integer - .config_screenBrightnessForVrSettingDefault), - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + .config_screenBrightnessForVrSettingDefault)); } else { mScreenBrightnessMinimumVr = vrMin; mScreenBrightnessMaximumVr = vrMax; @@ -3590,8 +3575,7 @@ public final class PowerManagerService extends SystemService mDozeScreenStateOverrideFromDreamManager = screenState; mDozeScreenBrightnessOverrideFromDreamManager = screenBrightness; mDozeScreenBrightnessOverrideFromDreamManagerFloat = - BrightnessSynchronizer.brightnessIntToFloat(mContext, - mDozeScreenBrightnessOverrideFromDreamManager); + BrightnessSynchronizer.brightnessIntToFloat(mDozeScreenBrightnessOverrideFromDreamManager); mDirty |= DIRTY_SETTINGS; updatePowerStateLocked(); } @@ -5393,6 +5377,29 @@ public final class PowerManagerService extends SystemService } } + /** + * If the user presses power while the proximity sensor is enabled and keeping + * the screen off, then turn the screen back on by telling display manager to + * ignore the proximity sensor. We don't turn off the proximity sensor because + * we still want it to be reenabled if it's state changes. + * + * @return True if the proximity sensor was successfully ignored and we should + * consume the key event. + */ + private boolean interceptPowerKeyDownInternal(KeyEvent event) { + synchronized (mLock) { + // DisplayPowerController only reports proximity positive (near) if it's + // positive and the proximity wasn't already being ignored. So it reliably + // also tells us that we're not already ignoring the proximity sensor. + if (mDisplayPowerRequest.useProximitySensor && mProximityPositive) { + mDisplayManagerInternal.ignoreProximitySensorUntilChanged(); + return true; + } + } + + return false; + } + @VisibleForTesting final class LocalService extends PowerManagerInternal { @Override @@ -5525,5 +5532,10 @@ public final class PowerManagerService extends SystemService public WakeData getLastWakeup() { return getLastWakeupInternal(); } + + @Override + public boolean interceptPowerKeyDown(KeyEvent event) { + return interceptPowerKeyDownInternal(event); + } } } diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index 3ec61fdda917..7467439905eb 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -18,7 +18,6 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.app.timezonedetector.ITimeZoneConfigurationListener; import android.app.timezonedetector.ITimeZoneDetectorService; import android.app.timezonedetector.ManualTimeZoneSuggestion; @@ -38,6 +37,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.IndentingPrintWriter; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -60,7 +60,8 @@ import java.util.Objects; * and making calls async, leaving the (consequently more testable) {@link TimeZoneDetectorStrategy} * implementation to deal with the logic around time zone detection. */ -public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub { +public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub + implements IBinder.DeathRecipient { private static final String TAG = "TimeZoneDetectorService"; @@ -104,9 +105,15 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy; + /** + * This sparse array acts as a map from userId to listeners running as that userId. User scoped + * as time zone detection configuration is partially user-specific, so different users can + * get different configuration. + */ @GuardedBy("mConfigurationListeners") @NonNull - private final ArrayList<ConfigListenerInfo> mConfigurationListeners = new ArrayList<>(); + private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners = + new SparseArray<>(); private static TimeZoneDetectorService create( @NonNull Context context, @NonNull Handler handler, @@ -188,18 +195,23 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub Objects.requireNonNull(listener); int userId = UserHandle.getCallingUserId(); - ConfigListenerInfo listenerInfo = new ConfigListenerInfo(userId, listener); - synchronized (mConfigurationListeners) { - if (mConfigurationListeners.contains(listenerInfo)) { + ArrayList<ITimeZoneConfigurationListener> listeners = + mConfigurationListeners.get(userId); + if (listeners != null && listeners.contains(listener)) { return; } try { - // Ensure the reference to the listener is removed if the client process dies. - listenerInfo.linkToDeath(); + if (listeners == null) { + listeners = new ArrayList<>(1); + mConfigurationListeners.put(userId, listeners); + } + + // Ensure the reference to the listener will be removed if the client process dies. + listener.asBinder().linkToDeath(this, 0 /* flags */); // Only add the listener if we can linkToDeath(). - mConfigurationListeners.add(listenerInfo); + listeners.add(listener); } catch (RemoteException e) { Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e); } @@ -213,21 +225,56 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub int userId = UserHandle.getCallingUserId(); synchronized (mConfigurationListeners) { - ConfigListenerInfo toRemove = new ConfigListenerInfo(userId, listener); - Iterator<ConfigListenerInfo> listenerIterator = mConfigurationListeners.iterator(); - while (listenerIterator.hasNext()) { - ConfigListenerInfo currentListenerInfo = listenerIterator.next(); - if (currentListenerInfo.equals(toRemove)) { - listenerIterator.remove(); - - // Stop listening for the client process to die. - try { - currentListenerInfo.unlinkToDeath(); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to unlinkToDeath() for listener=" + listener, e); + boolean removedListener = false; + ArrayList<ITimeZoneConfigurationListener> userListeners = + mConfigurationListeners.get(userId); + if (userListeners.remove(listener)) { + // Stop listening for the client process to die. + listener.asBinder().unlinkToDeath(this, 0 /* flags */); + removedListener = true; + } + if (!removedListener) { + Slog.w(TAG, "Client asked to remove listenener=" + listener + + ", but no listeners were removed." + + " mConfigurationListeners=" + mConfigurationListeners); + } + } + } + + @Override + public void binderDied() { + // Should not be used as binderDied(IBinder who) is overridden. + Slog.wtf(TAG, "binderDied() called unexpectedly."); + } + + /** + * Called when one of the ITimeZoneConfigurationListener processes dies before calling + * {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}. + */ + @Override + public void binderDied(IBinder who) { + synchronized (mConfigurationListeners) { + boolean removedListener = false; + final int userCount = mConfigurationListeners.size(); + for (int i = 0; i < userCount; i++) { + ArrayList<ITimeZoneConfigurationListener> userListeners = + mConfigurationListeners.valueAt(i); + Iterator<ITimeZoneConfigurationListener> userListenerIterator = + userListeners.iterator(); + while (userListenerIterator.hasNext()) { + ITimeZoneConfigurationListener userListener = userListenerIterator.next(); + if (userListener.asBinder().equals(who)) { + userListenerIterator.remove(); + removedListener = true; + break; } } } + if (!removedListener) { + Slog.w(TAG, "Notified of binder death for who=" + who + + ", but did not remove any listeners." + + " mConfigurationListeners=" + mConfigurationListeners); + } } } @@ -243,14 +290,24 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub // problem. synchronized (mConfigurationListeners) { - for (ConfigListenerInfo listenerInfo : mConfigurationListeners) { + final int userCount = mConfigurationListeners.size(); + for (int userIndex = 0; userIndex < userCount; userIndex++) { + int userId = mConfigurationListeners.keyAt(userIndex); TimeZoneConfiguration configuration = - mTimeZoneDetectorStrategy.getConfiguration(listenerInfo.getUserId()); - try { - listenerInfo.getListener().onChange(configuration); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to notify listener=" - + listenerInfo + " of updated configuration=" + configuration, e); + mTimeZoneDetectorStrategy.getConfiguration(userId); + + ArrayList<ITimeZoneConfigurationListener> listeners = + mConfigurationListeners.valueAt(userIndex); + final int listenerCount = listeners.size(); + for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) { + ITimeZoneConfigurationListener listener = listeners.get(listenerIndex); + try { + listener.onChange(configuration); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to notify listener=" + listener + + " for userId=" + userId + + " of updated configuration=" + configuration, e); + } } } } @@ -338,66 +395,5 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub (new TimeZoneDetectorShellCommand(this)).exec( this, in, out, err, args, callback, resultReceiver); } - - private class ConfigListenerInfo implements IBinder.DeathRecipient { - private final @UserIdInt int mUserId; - private final ITimeZoneConfigurationListener mListener; - - ConfigListenerInfo( - @UserIdInt int userId, @NonNull ITimeZoneConfigurationListener listener) { - this.mUserId = userId; - this.mListener = Objects.requireNonNull(listener); - } - - @UserIdInt int getUserId() { - return mUserId; - } - - ITimeZoneConfigurationListener getListener() { - return mListener; - } - - void linkToDeath() throws RemoteException { - mListener.asBinder().linkToDeath(this, 0 /* flags */); - } - - void unlinkToDeath() throws RemoteException { - mListener.asBinder().unlinkToDeath(this, 0 /* flags */); - } - - @Override - public void binderDied() { - synchronized (mConfigurationListeners) { - Slog.i(TAG, "Configuration listener client died: " + this); - mConfigurationListeners.remove(this); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ConfigListenerInfo that = (ConfigListenerInfo) o; - return mUserId == that.mUserId - && mListener.equals(that.mListener); - } - - @Override - public int hashCode() { - return Objects.hash(mUserId, mListener); - } - - @Override - public String toString() { - return "ConfigListenerInfo{" - + "mUserId=" + mUserId - + ", mListener=" + mListener - + '}'; - } - } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 1b4fac6f407a..e573d362fef4 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1675,7 +1675,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) { int lockTaskLaunchMode = aInfo.lockTaskLaunchMode; - if (aInfo.applicationInfo.isPrivilegedApp() + // Non-priv apps are not allowed to use always or never, fall back to default + if (!aInfo.applicationInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 627361d780a2..31a9c5d4242c 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2999,13 +2999,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void stopLockTaskModeByToken(IBinder token) { - synchronized (mGlobalLock) { - final ActivityRecord r = ActivityRecord.forTokenLocked(token); - if (r == null) { - return; - } - stopLockTaskModeInternal(r.getTask(), false /* isSystemCaller */); - } + stopLockTaskModeInternal(token, false /* isSystemCaller */); } /** @@ -3047,11 +3041,19 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - private void stopLockTaskModeInternal(@Nullable Task task, boolean isSystemCaller) { + private void stopLockTaskModeInternal(@Nullable IBinder token, boolean isSystemCaller) { final int callingUid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { synchronized (mGlobalLock) { + Task task = null; + if (token != null) { + final ActivityRecord r = ActivityRecord.forTokenLocked(token); + if (r == null) { + return; + } + task = r.getTask(); + } getLockTaskController().stopLockTaskMode(task, isSystemCaller, callingUid); } // Launch in-call UI if a call is ongoing. This is necessary to allow stopping the lock diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 5cea786c3367..1c9743041923 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -22,7 +22,6 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATI import android.annotation.NonNull; import android.annotation.Nullable; -import android.graphics.ColorSpace; import android.graphics.PixelFormat; import android.graphics.Rect; import android.hardware.HardwareBuffer; @@ -89,8 +88,7 @@ class SurfaceFreezer { if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) { return; } - mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, buffer, - screenshotBuffer.getColorSpace(), mLeash); + mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, screenshotBuffer, mLeash); } } @@ -135,8 +133,12 @@ class SurfaceFreezer { cropBounds = new Rect(bounds); cropBounds.offsetTo(0, 0); } - return SurfaceControl.captureLayers(target, cropBounds, 1.f /* frameScale */, - PixelFormat.RGBA_8888); + SurfaceControl.LayerCaptureArgs captureArgs = + new SurfaceControl.LayerCaptureArgs.Builder(target) + .setSourceCrop(cropBounds) + .setCaptureSecureLayers(true) + .build(); + return SurfaceControl.captureLayers(captureArgs); } class Snapshot { @@ -146,21 +148,23 @@ class SurfaceFreezer { /** * @param t Transaction to create the thumbnail in. - * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with. + * @param screenshotBuffer A thumbnail or placeholder for thumbnail to initialize with. */ Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t, - HardwareBuffer thumbnailHeader, ColorSpace colorSpace, SurfaceControl parent) { + SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer, SurfaceControl parent) { Surface drawSurface = surfaceFactory.get(); // We can't use a delegating constructor since we need to // reference this::onAnimationFinished - final int width = thumbnailHeader.getWidth(); - final int height = thumbnailHeader.getHeight(); + HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer(); + final int width = hardwareBuffer.getWidth(); + final int height = hardwareBuffer.getHeight(); mSurfaceControl = mAnimatable.makeAnimationLeash() .setName("snapshot anim: " + mAnimatable.toString()) .setBufferSize(width, height) .setFormat(PixelFormat.TRANSLUCENT) .setParent(parent) + .setSecure(screenshotBuffer.containsSecureLayers()) .setCallsite("SurfaceFreezer.Snapshot") .build(); @@ -168,7 +172,8 @@ class SurfaceFreezer { // Transfer the thumbnail to the surface drawSurface.copyFrom(mSurfaceControl); - drawSurface.attachAndQueueBufferWithColorSpace(thumbnailHeader, colorSpace); + drawSurface.attachAndQueueBufferWithColorSpace(hardwareBuffer, + screenshotBuffer.getColorSpace()); drawSurface.release(); t.show(mSurfaceControl); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index a58c5646858b..70c30c9180d7 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1177,12 +1177,19 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio boolean handleAppDied() { mAtm.mStackSupervisor.removeHistoryRecords(this); - final boolean isRemoved = isRemoved(); boolean hasVisibleActivities = false; if (mInactiveActivities != null && !mInactiveActivities.isEmpty()) { // Make sure that all activities in this process are handled. mActivities.addAll(mInactiveActivities); } + if (isRemoved()) { + // The package of the died process should be force-stopped, so make its activities as + // finishing to prevent the process from being started again if the next top (or being + // visible) activity also resides in the same process. This must be done before removal. + for (int i = mActivities.size() - 1; i >= 0; i--) { + mActivities.get(i).makeFinishingLocked(); + } + } for (int i = mActivities.size() - 1; i >= 0; i--) { final ActivityRecord r = mActivities.get(i); if (r.mVisibleRequested || r.isVisible()) { @@ -1191,12 +1198,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // is not yet committed, so isVisible()=true. hasVisibleActivities = true; } - if (isRemoved) { - // The package of the died process should be force-stopped, so make its activities - // as finishing to prevent the process from being started again if the next top (or - // being visible) activity also resides in the same process. - r.makeFinishingLocked(); - } final Task rootTask = r.getRootTask(); if (rootTask != null) { diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 0202c88009fd..935dffe5021e 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -75,6 +75,12 @@ using android::base::ParseUint; using android::base::StringPrintf; +// Maximum allowable delay value in a vibration pattern before +// which the delay will be truncated. +static constexpr std::chrono::duration MAX_VIBRATE_PATTERN_DELAY = 100s; +static constexpr std::chrono::milliseconds MAX_VIBRATE_PATTERN_DELAY_MILLIS = + std::chrono::duration_cast<std::chrono::milliseconds>(MAX_VIBRATE_PATTERN_DELAY); + namespace android { // The exponent used to calculate the pointer speed scaling factor. @@ -1636,17 +1642,19 @@ static void nativeVibrate(JNIEnv* env, jclass /* clazz */, jlong ptr, jint devic patternObj, nullptr)); jint* amplitudes = static_cast<jint*>(env->GetPrimitiveArrayCritical(amplitudesObj, nullptr)); - std::vector<VibrationElement> pattern(patternSize); + std::vector<VibrationElement> elements(patternSize); for (size_t i = 0; i < patternSize; i++) { - jlong duration = - max(min(patternMillis[i], (jlong)MAX_VIBRATE_PATTERN_DELAY_MSECS), (jlong)0); - pattern[i].duration = std::chrono::milliseconds(duration); - pattern[i].channels = {amplitudes[i]}; + // VibrationEffect.validate guarantees duration > 0. + std::chrono::milliseconds duration(patternMillis[i]); + elements[i].duration = std::min(duration, MAX_VIBRATE_PATTERN_DELAY_MILLIS); + // TODO: (b/161629089) apply channel specific amplitudes from development API. + elements[i].channels = {static_cast<uint8_t>(amplitudes[i]), + static_cast<uint8_t>(amplitudes[i])}; } env->ReleasePrimitiveArrayCritical(patternObj, patternMillis, JNI_ABORT); env->ReleasePrimitiveArrayCritical(amplitudesObj, amplitudes, JNI_ABORT); - im->getInputManager()->getReader()->vibrate(deviceId, pattern, repeat, token); + im->getInputManager()->getReader()->vibrate(deviceId, elements, repeat, token); } static void nativeCancelVibrate(JNIEnv* /* env */, diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index 37bf66491882..33317a38853e 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -19,6 +19,8 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.people.ConversationChannel; +import android.app.people.IPeopleManager; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; import android.app.prediction.AppTarget; @@ -26,8 +28,11 @@ import android.app.prediction.AppTargetEvent; import android.app.prediction.IPredictionCallback; import android.content.Context; import android.content.pm.ParceledListSlice; +import android.os.Binder; import android.os.CancellationSignal; +import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; @@ -35,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; import com.android.server.people.data.DataManager; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -68,6 +74,7 @@ public class PeopleService extends SystemService { @Override public void onStart() { + publishBinderService(Context.PEOPLE_SERVICE, new BinderService()); publishLocalService(PeopleServiceInternal.class, new LocalService()); } @@ -81,6 +88,38 @@ public class PeopleService extends SystemService { mDataManager.onUserStopping(user.getUserIdentifier()); } + /** + * Enforces that only the system or root UID can make certain calls. + * + * @param message used as message if SecurityException is thrown + * @throws SecurityException if the caller is not system or root + */ + private static void enforceSystemOrRoot(String message) { + int uid = Binder.getCallingUid(); + if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) { + throw new SecurityException("Only system may " + message); + } + } + + private final class BinderService extends IPeopleManager.Stub { + + @Override + public ParceledListSlice<ConversationChannel> getRecentConversations() { + enforceSystemOrRoot("get recent conversations"); + return new ParceledListSlice<>(new ArrayList<>()); + } + + @Override + public void removeRecentConversation(String packageName, int userId, String shortcutId) { + enforceSystemOrRoot("remove a recent conversation"); + } + + @Override + public void removeAllRecentConversations() { + enforceSystemOrRoot("remove all recent conversations"); + } + } + @VisibleForTesting final class LocalService extends PeopleServiceInternal { diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java index cd9b6aca72e0..cbebe6984794 100644 --- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java +++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceRoboTest.java @@ -1092,9 +1092,11 @@ public class BackupManagerServiceRoboTest { registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserOneId, /* shouldGrantPermission */ false); - backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT); + backupManagerService.beginRestoreSession(mUserOneId, TEST_PACKAGE, TEST_TRANSPORT, + OperationType.BACKUP); - verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); + verify(mUserOneService).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT, + OperationType.BACKUP); } /** Test that the backup service does not route methods for non-registered users. */ @@ -1104,9 +1106,11 @@ public class BackupManagerServiceRoboTest { registerUser(backupManagerService, mUserOneId, mUserOneService); setCallerAndGrantInteractUserPermission(mUserTwoId, /* shouldGrantPermission */ false); - backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT); + backupManagerService.beginRestoreSession(mUserTwoId, TEST_PACKAGE, TEST_TRANSPORT, + OperationType.BACKUP); - verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT); + verify(mUserOneService, never()).beginRestoreSession(TEST_PACKAGE, TEST_TRANSPORT, + OperationType.BACKUP); } /** Test that the backup service routes methods correctly to the user that requests it. */ diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 6184c4ed7f1a..09e3bfe9cf20 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -794,7 +794,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); doThrow(SecurityException.class) .when(mBackupManagerService) - .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt()); + .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt()); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1); runTask(task); @@ -812,7 +812,7 @@ public class KeyValueBackupTaskTest { setUpAgent(PACKAGE_1); doThrow(SecurityException.class) .when(mBackupManagerService) - .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt()); + .bindToAgentSynchronous(argThat(applicationInfo(PACKAGE_1)), anyInt(), anyInt()); KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1); runTask(task); @@ -2593,11 +2593,13 @@ public class KeyValueBackupTaskTest { if (packageData.available) { doReturn(backupAgentBinder) .when(mBackupManagerService) - .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt()); + .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(), + anyInt()); } else { doReturn(null) .when(mBackupManagerService) - .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt()); + .bindToAgentSynchronous(argThat(applicationInfo(packageData)), anyInt(), + anyInt()); } return new AgentMock(backupAgentBinder, backupAgent); } catch (RemoteException e) { diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 3fc421dfb6e9..5883c1cb5995 100644 --- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -57,6 +57,7 @@ import com.android.server.backup.internal.BackupHandler; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils; import com.android.server.backup.testing.TransportTestUtils.TransportMock; +import com.android.server.backup.utils.BackupEligibilityRules; import com.android.server.testing.shadows.ShadowApplicationPackageManager; import com.android.server.testing.shadows.ShadowEventLog; import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask; @@ -96,6 +97,7 @@ public class ActiveRestoreSessionTest { @Mock private TransportManager mTransportManager; @Mock private IRestoreObserver mObserver; @Mock private IBackupManagerMonitor mMonitor; + @Mock private BackupEligibilityRules mBackupEligibilityRules; private ShadowLooper mShadowBackupLooper; private ShadowApplication mShadowApplication; private UserBackupManagerService.BackupWakeLock mWakeLock; @@ -576,7 +578,8 @@ public class ActiveRestoreSessionTest { private IRestoreSession createActiveRestoreSession( String packageName, TransportData transport) { return new ActiveRestoreSession( - mBackupManagerService, packageName, transport.transportName); + mBackupManagerService, packageName, transport.transportName, + mBackupEligibilityRules); } private IRestoreSession createActiveRestoreSessionWithRestoreSets( @@ -584,7 +587,8 @@ public class ActiveRestoreSessionTest { throws RemoteException { ActiveRestoreSession restoreSession = new ActiveRestoreSession( - mBackupManagerService, packageName, transport.transportName); + mBackupManagerService, packageName, transport.transportName, + mBackupEligibilityRules); restoreSession.setRestoreSets(restoreSets); return restoreSession; } diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt index bc478b0e2c90..207f10a3027b 100644 --- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt @@ -104,8 +104,11 @@ class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() { } private val tempFolder = TemporaryFolder() + + // TODO(b/160159215): Use START_STOP rather than FULL once it's fixed. This will drastically + // improve pre/post-submit times. private val preparer: SystemPreparer = SystemPreparer(tempFolder, - SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device } + SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device } @get:Rule val rules = RuleChain.outerRule(tempFolder).let { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 1b2711d3938b..82726c7ea20c 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -501,7 +501,7 @@ public class MockingOomAdjusterTests { public void testUpdateOomAdj_DoOne_Backup() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true)); - BackupRecord backupTarget = new BackupRecord(null, 0, 0); + BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0); backupTarget.app = app; doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt()); sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; @@ -803,7 +803,7 @@ public class MockingOomAdjusterTests { ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); bindService(app, client, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class)); - BackupRecord backupTarget = new BackupRecord(null, 0, 0); + BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0); backupTarget.app = client; doReturn(backupTarget).when(sService.mBackupTargets).get(anyInt()); sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 6450a0fc1453..763654d24047 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -42,6 +42,7 @@ import android.os.SystemClock; import android.testing.DexmakerShareClassLoaderRule; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; import androidx.test.InstrumentationRegistry; @@ -87,6 +88,8 @@ public class TouchExplorerTest { private MotionEvent mLastEvent; private TestHandler mHandler; private TouchExplorer mTouchExplorer; + private Context mContext; + private int mTouchSlop; private long mLastDownTime = Integer.MIN_VALUE; // mock package-private GestureManifold class @@ -121,12 +124,13 @@ public class TouchExplorerTest { if (Looper.myLooper() == null) { Looper.prepare(); } - Context context = InstrumentationRegistry.getContext(); - AccessibilityManagerService ams = new AccessibilityManagerService(context); + mContext = InstrumentationRegistry.getContext(); + mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + AccessibilityManagerService ams = new AccessibilityManagerService(mContext); GestureManifold detector = mock(GestureManifold.class); mCaptor = new EventCaptor(); mHandler = new TestHandler(); - mTouchExplorer = new TouchExplorer(context, ams, detector, mHandler); + mTouchExplorer = new TouchExplorer(mContext, ams, detector, mHandler); mTouchExplorer.setNext(mCaptor); } @@ -354,12 +358,12 @@ public class TouchExplorerTest { break; case STATE_DRAGGING_2FINGERS: goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER); - moveEachPointers(mLastEvent, p(10, 0), p(10, 0)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(mTouchSlop, 0)); send(mLastEvent); break; case STATE_PINCH_2FINGERS: goFromStateClearTo(STATE_DRAGGING_2FINGERS); - moveEachPointers(mLastEvent, p(10, 0), p(-10, 1)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(-mTouchSlop, 1)); send(mLastEvent); break; case STATE_MOVING_3FINGERS: diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index 960a7ab52c22..ef2365e6da3e 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -16,7 +16,6 @@ package com.android.server.hdmi; import static com.android.server.hdmi.Constants.ADDR_BROADCAST; -import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; @@ -62,6 +61,7 @@ public class HdmiCecLocalDevicePlaybackTest { private TestLooper mTestLooper = new TestLooper(); private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>(); private int mPlaybackPhysicalAddress; + private int mPlaybackLogicalAddress; private boolean mWokenUp; private boolean mStandby; @@ -129,6 +129,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress = 0x2000; mNativeWrapper.setPhysicalAddress(mPlaybackPhysicalAddress); mTestLooper.dispatchAll(); + mPlaybackLogicalAddress = mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress(); mNativeWrapper.clearResultMessages(); } @@ -144,7 +145,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); @@ -165,7 +166,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); @@ -186,7 +187,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); @@ -207,7 +208,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); @@ -230,7 +231,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); @@ -253,7 +254,7 @@ public class HdmiCecLocalDevicePlaybackTest { mPlaybackPhysicalAddress); HdmiCecMessage expectedMessage = - HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); @@ -262,6 +263,112 @@ public class HdmiCecLocalDevicePlaybackTest { assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage); } + @Test + public void handleRoutingChange_otherDevice_None() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.NONE; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleRoutingChange_otherDevice_StandbyNow() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isTrue(); + } + + @Test + public void handleRoutingChange_otherDevice_StandbyNow_InactiveSource() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(false); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleRoutingChange_sameDevice_StandbyNow_ActiveSource() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingChange(ADDR_TV, 0x0000, + mPlaybackPhysicalAddress); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleRoutingInformation_otherDevice_None() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.NONE; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleRoutingInformation_otherDevice_StandbyNow() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isTrue(); + } + + @Test + public void handleRoutingInformation_otherDevice_StandbyNow_InactiveSource() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(false); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleRoutingInformation_sameDevice_StandbyNow_ActiveSource() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildRoutingInformation(ADDR_TV, + mPlaybackPhysicalAddress); + assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue(); + assertThat(mStandby).isFalse(); + } + // Playback device does not handle routing control related feature right now @Ignore("b/120845532") @Test @@ -442,7 +549,7 @@ public class HdmiCecLocalDevicePlaybackTest { mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = HdmiProperties.power_state_change_on_active_source_lost_values.NONE; mStandby = false; - HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue(); mTestLooper.dispatchAll(); @@ -465,7 +572,7 @@ public class HdmiCecLocalDevicePlaybackTest { mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; mStandby = false; - HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, + HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress); assertThat(mHdmiCecLocalDevicePlayback.handleActiveSource(message)).isTrue(); mTestLooper.dispatchAll(); @@ -629,4 +736,43 @@ public class HdmiCecLocalDevicePlaybackTest { mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress()); assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue(); } + + @Test + public void handleSetStreamPath_otherDevice_None() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.NONE; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } + + @Test + public void handleSetStreamPath_otherDevice_StandbyNow() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(true); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isTrue(); + } + + @Test + public void handleSetStreamPath_otherDevice_StandbyNow_InactiveSource() { + mHdmiCecLocalDevicePlayback.mPowerStateChangeOnActiveSourceLost = + HdmiProperties.power_state_change_on_active_source_lost_values.STANDBY_NOW; + mHdmiCecLocalDevicePlayback.setIsActiveSource(false); + mStandby = false; + HdmiCecMessage message = + HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV, 0x5000); + assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(message)).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isFalse(); + assertThat(mStandby).isFalse(); + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index db56657e208c..b2512d3ed8ca 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -69,6 +69,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; @Presubmit @RunWith(JUnit4.class) @@ -88,6 +89,8 @@ public class AppsFilterTest { AppsFilter.FeatureConfig mFeatureConfigMock; @Mock AppsFilter.StateProvider mStateProvider; + @Mock + Executor mMockExecutor; private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>(); @@ -184,10 +187,15 @@ public class AppsFilterTest { doAnswer(invocation -> { ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0)) .currentState(mExisting, USER_INFO_LIST); - return null; + return new Object(); }).when(mStateProvider) .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class)); + doAnswer(invocation -> { + ((Runnable) invocation.getArgument(0)).run(); + return new Object(); + }).when(mMockExecutor).execute(any(Runnable.class)); + when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer( (Answer<Boolean>) invocation -> @@ -198,7 +206,8 @@ public class AppsFilterTest { @Test public void testSystemReadyPropogates() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); appsFilter.onSystemReady(); verify(mFeatureConfigMock).onSystemReady(); } @@ -206,7 +215,8 @@ public class AppsFilterTest { @Test public void testQueriesAction_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -222,7 +232,8 @@ public class AppsFilterTest { @Test public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); final Signature frameworkSignature = Mockito.mock(Signature.class); final PackageParser.SigningDetails frameworkSigningDetails = new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); @@ -260,7 +271,8 @@ public class AppsFilterTest { @Test public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -277,7 +289,8 @@ public class AppsFilterTest { @Test public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -294,7 +307,8 @@ public class AppsFilterTest { @Test public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -312,7 +326,8 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -328,7 +343,8 @@ public class AppsFilterTest { @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -348,7 +364,8 @@ public class AppsFilterTest { @Test public void testNoQueries_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -364,7 +381,8 @@ public class AppsFilterTest { @Test public void testForceQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -381,7 +399,7 @@ public class AppsFilterTest { public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, - false, null); + false, null, mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -399,7 +417,8 @@ public class AppsFilterTest { @Test public void testSystemSignedTarget_DoesntFilter() throws CertificateException { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); appsFilter.onSystemReady(); final Signature frameworkSignature = Mockito.mock(Signature.class); @@ -428,7 +447,7 @@ public class AppsFilterTest { public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, - false, null); + false, null, mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -446,7 +465,7 @@ public class AppsFilterTest { public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, - true /* system force queryable */, null); + true /* system force queryable */, null, mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -463,7 +482,8 @@ public class AppsFilterTest { @Test public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -481,7 +501,8 @@ public class AppsFilterTest { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -497,7 +518,8 @@ public class AppsFilterTest { @Test public void testSystemUid_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -512,7 +534,8 @@ public class AppsFilterTest { @Test public void testSystemUidSecondaryUser_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -528,7 +551,8 @@ public class AppsFilterTest { @Test public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -542,7 +566,8 @@ public class AppsFilterTest { @Test public void testNoTargetPackage_filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -599,7 +624,8 @@ public class AppsFilterTest { } return Collections.emptyMap(); } - }); + }, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -671,7 +697,8 @@ public class AppsFilterTest { } return Collections.emptyMap(); } - }); + }, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -696,7 +723,8 @@ public class AppsFilterTest { @Test public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -712,7 +740,8 @@ public class AppsFilterTest { @Test public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -728,7 +757,8 @@ public class AppsFilterTest { @Test public void testOriginatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -744,7 +774,8 @@ public class AppsFilterTest { @Test public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -760,7 +791,8 @@ public class AppsFilterTest { @Test public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -782,7 +814,8 @@ public class AppsFilterTest { @Test public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null, + mMockExecutor); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 153634548c17..8034cacc6923 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -170,7 +170,7 @@ public class TimeZoneDetectorServiceTest { ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class); try { mTimeZoneDetectorService.removeConfigurationListener(mockListener); - fail(); + fail("Expected a SecurityException"); } finally { verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 1d75967756c3..88b1d191dc4d 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -16,6 +16,7 @@ package com.android.server; +import android.Manifest; import android.app.AlarmManager; import android.app.IUiModeManager; import android.content.BroadcastReceiver; @@ -24,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Handler; @@ -67,6 +69,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -230,6 +233,17 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { } @Test + public void setNightModeActivated_permissiontoChangeOtherUsers() throws RemoteException { + SystemService.TargetUser user = mock(SystemService.TargetUser.class); + doReturn(9).when(user).getUserIdentifier(); + mUiManagerService.onUserSwitching(user, user); + when(mContext.checkCallingOrSelfPermission( + eq(Manifest.permission.INTERACT_ACROSS_USERS))) + .thenReturn(PackageManager.PERMISSION_DENIED); + assertFalse(mService.setNightModeActivated(true)); + } + + @Test public void autoNightModeSwitch_batterySaverOn() throws RemoteException { mService.setNightMode(MODE_NIGHT_NO); when(mTwilightState.isNight()).thenReturn(false); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 980772bb08bc..5b2d738eb760 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4856,6 +4856,70 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws + Exception { + final String testPackage = "testPackageName"; + assertEquals(0, mService.mToastQueue.size()); + mService.isSystemUid = true; + + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + .thenReturn(false); + + // notifications from this package are blocked by the user + mService.setPreferencesHelper(mPreferencesHelper); + when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE); + + setAppInForegroundForToasts(mUid, false); + + // enqueue toast -> toast should still enqueue + ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(), + new TestableToastCallback(), 2000, 0); + assertEquals(1, mService.mToastQueue.size()); + verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any()); + } + + @Test + public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws + Exception { + final String testPackage = "testPackageName"; + assertEquals(0, mService.mToastQueue.size()); + mService.isSystemUid = false; + + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + .thenReturn(false); + + setAppInForegroundForToasts(mUid, true); + + // enqueue toast -> toast should still enqueue + ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), + "Text", 2000, 0, null); + assertEquals(1, mService.mToastQueue.size()); + verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); + } + + @Test + public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws + Exception { + final String testPackage = "testPackageName"; + assertEquals(0, mService.mToastQueue.size()); + mService.isSystemUid = false; + + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) + .thenReturn(false); + + setAppInForegroundForToasts(mUid, false); + + // enqueue toast -> toast should still enqueue + ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(), + "Text", 2000, 0, null); + assertEquals(1, mService.mToastQueue.size()); + verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); + } + + @Test public void testTextToastsCallStatusBar() throws Exception { final String testPackage = "testPackageName"; assertEquals(0, mService.mToastQueue.size()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index e3830f686a42..6061f13fcee5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -22,6 +22,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; +import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; @@ -69,10 +73,8 @@ 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.ArgumentMatchers.same; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import android.app.ActivityManager.TaskSnapshot; @@ -84,6 +86,7 @@ import android.app.servertransaction.PauseActivityItem; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; @@ -1685,6 +1688,32 @@ public class ActivityRecordTests extends WindowTestsBase { assertFalse(mActivity.canTurnScreenOn()); } + @Test + public void testGetLockTaskLaunchMode() { + final ActivityOptions options = ActivityOptions.makeBasic().setLockTaskEnabled(true); + mActivity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; + assertEquals(LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED, + ActivityRecord.getLockTaskLaunchMode(mActivity.info, options)); + + mActivity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; + assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, + ActivityRecord.getLockTaskLaunchMode(mActivity.info, null /*options*/)); + + mActivity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; + assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, + ActivityRecord.getLockTaskLaunchMode(mActivity.info, null /*options*/)); + + mActivity.info.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; + mActivity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; + assertEquals(LOCK_TASK_LAUNCH_MODE_ALWAYS, + ActivityRecord.getLockTaskLaunchMode(mActivity.info, null /*options*/)); + + mActivity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; + assertEquals(LOCK_TASK_LAUNCH_MODE_NEVER, + ActivityRecord.getLockTaskLaunchMode(mActivity.info, null /*options*/)); + + } + /** * Creates an activity on display. For non-default display request it will also create a new * display with custom DisplayInfo. diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 2fd6c4249f99..78556ef41edb 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -763,11 +763,12 @@ public class UsageStatsService extends SystemService implements return; } - final LinkedList<Event> events = mReportedEvents.get(userId, new LinkedList<>()); - events.add(event); - if (mReportedEvents.get(userId) == null) { + LinkedList<Event> events = mReportedEvents.get(userId); + if (events == null) { + events = new LinkedList<>(); mReportedEvents.put(userId, events); } + events.add(event); if (events.size() == 1) { // Every time a file is persisted to disk, mReportedEvents is cleared for this user // so trigger a flush to disk every time the first event has been added. diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index 2e4d390ceb60..c0658fe4422e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -84,7 +84,7 @@ class CloseImeAutoOpenWindowToHomeTest( navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible(bugId = 140855415) noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false) - navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(rotation, Surface.ROTATION_0) imeLayerBecomesInvisible(bugId = 141458352) imeAppLayerBecomesInvisible(testApp, bugId = 153739621) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 1c0da4f920bb..dcf308533ee6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -92,7 +92,7 @@ open class CloseImeWindowToHomeTest( navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible(bugId = 140855415) noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false) - navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(rotation, Surface.ROTATION_0) imeLayerBecomesInvisible(bugId = 153739621) imeAppLayerBecomesInvisible(testApp, bugId = 153739621) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt index c2ebcc2c4286..91ec211805f7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt @@ -90,7 +90,7 @@ class OpenAppToSplitScreenTest( navBarLayerIsAlwaysVisible() statusBarLayerIsAlwaysVisible() noUncoveredRegions(rotation) - navBarLayerRotatesAndScales(rotation) + navBarLayerRotatesAndScales(rotation, bugId = 140855415) statusBarLayerRotatesScales(rotation) all("dividerLayerBecomesVisible") { diff --git a/tests/SilkFX/Android.bp b/tests/SilkFX/Android.bp new file mode 100644 index 000000000000..ca0a091e65bb --- /dev/null +++ b/tests/SilkFX/Android.bp @@ -0,0 +1,22 @@ +// +// Copyright (C) 2010 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. +// + +android_test { + name: "SilkFX", + srcs: ["**/*.java", "**/*.kt"], + platform_apis: true, + certificate: "platform", +} diff --git a/tests/SilkFX/AndroidManifest.xml b/tests/SilkFX/AndroidManifest.xml new file mode 100644 index 000000000000..ca9550a9eeab --- /dev/null +++ b/tests/SilkFX/AndroidManifest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 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. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.test.silkfx"> + + <uses-sdk android:minSdkVersion="30"/> + + <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" /> + + <application android:label="SilkFX" + android:theme="@android:style/Theme.Material"> + + <activity android:name=".Main" + android:label="SilkFX Demos" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.DEFAULT"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + + <activity android:name=".app.CommonDemoActivity" /> + + <activity android:name=".hdr.GlowActivity" + android:label="Glow Examples"/> + + </application> +</manifest> diff --git a/tests/SilkFX/res/drawable-nodpi/dark_notification.png b/tests/SilkFX/res/drawable-nodpi/dark_notification.png Binary files differnew file mode 100644 index 000000000000..6de6c2ae785c --- /dev/null +++ b/tests/SilkFX/res/drawable-nodpi/dark_notification.png diff --git a/tests/SilkFX/res/drawable-nodpi/light_notification.png b/tests/SilkFX/res/drawable-nodpi/light_notification.png Binary files differnew file mode 100644 index 000000000000..81a67cd3d388 --- /dev/null +++ b/tests/SilkFX/res/drawable-nodpi/light_notification.png diff --git a/tests/SilkFX/res/layout/bling_notifications.xml b/tests/SilkFX/res/layout/bling_notifications.xml new file mode 100644 index 000000000000..6d266b701a68 --- /dev/null +++ b/tests/SilkFX/res/layout/bling_notifications.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <com.android.test.silkfx.hdr.BlingyNotification + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:src="@drawable/dark_notification" /> + + <com.android.test.silkfx.hdr.BlingyNotification + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:src="@drawable/light_notification" /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/SilkFX/res/layout/color_mode_controls.xml b/tests/SilkFX/res/layout/color_mode_controls.xml new file mode 100644 index 000000000000..c0c0bab8a605 --- /dev/null +++ b/tests/SilkFX/res/layout/color_mode_controls.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<com.android.test.silkfx.common.ColorModeControls + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:id="@+id/current_mode" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <Button + android:id="@+id/mode_default" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="Default (sRGB)" /> + + <Button + android:id="@+id/mode_wide" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="Wide Gamut (P3)" /> + + <Button + android:id="@+id/mode_hdr" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="HDR" /> + + <Button + android:id="@+id/mode_hdr10" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:text="HDR10" /> + + </LinearLayout> + +</com.android.test.silkfx.common.ColorModeControls>
\ No newline at end of file diff --git a/tests/SilkFX/res/layout/common_base.xml b/tests/SilkFX/res/layout/common_base.xml new file mode 100644 index 000000000000..944c6846fbf7 --- /dev/null +++ b/tests/SilkFX/res/layout/common_base.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <include layout="@layout/color_mode_controls" /> + + <FrameLayout android:id="@+id/demo_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <View + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <com.android.test.silkfx.common.HDRIndicator + android:layout_width="match_parent" + android:layout_height="50dp" + android:layout_margin="8dp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/SilkFX/res/layout/hdr_glows.xml b/tests/SilkFX/res/layout/hdr_glows.xml new file mode 100644 index 000000000000..b6050645866a --- /dev/null +++ b/tests/SilkFX/res/layout/hdr_glows.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <include layout="@layout/color_mode_controls" /> + + <com.android.test.silkfx.hdr.GlowingCard + android:layout_width="match_parent" + android:layout_height="100dp" + android:layout_margin="8dp" /> + + <com.android.test.silkfx.hdr.GlowingCard + android:id="@+id/card2" + android:layout_width="match_parent" + android:layout_height="100dp" + android:layout_margin="8dp"/> + + <com.android.test.silkfx.hdr.RadialGlow + android:layout_width="match_parent" + android:layout_height="200dp" + android:layout_margin="8dp" /> + + <View + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + <com.android.test.silkfx.common.HDRIndicator + android:layout_width="match_parent" + android:layout_height="50dp" + android:layout_margin="8dp" /> + +</LinearLayout>
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/Main.kt b/tests/SilkFX/src/com/android/test/silkfx/Main.kt new file mode 100644 index 000000000000..76e62a6c8cff --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/Main.kt @@ -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.test.silkfx + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.BaseExpandableListAdapter +import android.widget.ExpandableListView +import android.widget.TextView +import com.android.test.silkfx.app.CommonDemoActivity +import com.android.test.silkfx.app.EXTRA_LAYOUT +import com.android.test.silkfx.app.EXTRA_TITLE +import com.android.test.silkfx.hdr.GlowActivity +import kotlin.reflect.KClass + +class Demo(val name: String, val makeIntent: (Context) -> Intent) { + constructor(name: String, activity: KClass<out Activity>) : this(name, { context -> + Intent(context, activity.java) + }) + constructor(name: String, layout: Int) : this(name, { context -> + Intent(context, CommonDemoActivity::class.java).apply { + putExtra(EXTRA_LAYOUT, layout) + putExtra(EXTRA_TITLE, name) + } + }) +} +data class DemoGroup(val groupName: String, val demos: List<Demo>) + +private val AllDemos = listOf( + DemoGroup("HDR", listOf( + Demo("Glow", GlowActivity::class), + Demo("Blingy Notifications", R.layout.bling_notifications) + )) +) + +class Main : Activity() { + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val list = ExpandableListView(this) + + setContentView(list) + + val inflater = LayoutInflater.from(this) + list.setAdapter(object : BaseExpandableListAdapter() { + override fun getGroup(groupPosition: Int): DemoGroup { + return AllDemos[groupPosition] + } + + override fun isChildSelectable(groupPosition: Int, childPosition: Int): Boolean = true + + override fun hasStableIds(): Boolean = true + + override fun getGroupView( + groupPosition: Int, + isExpanded: Boolean, + convertView: View?, + parent: ViewGroup? + ): View { + val view = (convertView ?: inflater.inflate( + android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView + view.text = AllDemos[groupPosition].groupName + return view + } + + override fun getChildrenCount(groupPosition: Int): Int { + return AllDemos[groupPosition].demos.size + } + + override fun getChild(groupPosition: Int, childPosition: Int): Demo { + return AllDemos[groupPosition].demos[childPosition] + } + + override fun getGroupId(groupPosition: Int): Long = groupPosition.toLong() + + override fun getChildView( + groupPosition: Int, + childPosition: Int, + isLastChild: Boolean, + convertView: View?, + parent: ViewGroup? + ): View { + val view = (convertView ?: inflater.inflate( + android.R.layout.simple_expandable_list_item_1, parent, false)) as TextView + view.text = AllDemos[groupPosition].demos[childPosition].name + return view + } + + override fun getChildId(groupPosition: Int, childPosition: Int): Long { + return (groupPosition.toLong() shl 32) or childPosition.toLong() + } + + override fun getGroupCount(): Int { + return AllDemos.size + } + }) + + list.setOnChildClickListener { _, _, groupPosition, childPosition, _ -> + val demo = AllDemos[groupPosition].demos[childPosition] + startActivity(demo.makeIntent(this)) + return@setOnChildClickListener true + } + + AllDemos.forEachIndexed { index, _ -> list.expandGroup(index) } + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt new file mode 100644 index 000000000000..89011b51b8d6 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/app/BaseDemoActivity.kt @@ -0,0 +1,77 @@ +/* + * 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.test.silkfx.app + +import android.app.Activity +import android.content.Context +import android.os.Bundle +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.MenuItem +import android.view.View + +open class BaseDemoActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val inflater = LayoutInflater.from(this) + inflater.factory2 = object : LayoutInflater.Factory2 { + private val sClassPrefixList = arrayOf( + "android.widget.", + "android.webkit.", + "android.app.", + null + ) + override fun onCreateView( + parent: View?, + name: String, + context: Context, + attrs: AttributeSet + ): View? { + return onCreateView(name, context, attrs) + } + + override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { + for (prefix in sClassPrefixList) { + try { + val view = inflater.createView(name, prefix, attrs) + if (view != null) { + if (view is WindowObserver) { + view.setWindow(window) + } + return view + } + } catch (e: ClassNotFoundException) { } + } + return null + } + } + } + + override fun onStart() { + super.onStart() + actionBar?.setDisplayHomeAsUpEnabled(true) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + if (item.itemId == android.R.id.home) { + onBackPressed() + return true + } + return super.onOptionsItemSelected(item) + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt new file mode 100644 index 000000000000..e0a0a20bc0a0 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/app/CommonDemoActivity.kt @@ -0,0 +1,45 @@ +/* + * 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.test.silkfx.app + +import com.android.test.silkfx.R +import android.os.Bundle +import android.view.LayoutInflater + +const val EXTRA_LAYOUT = "layout" +const val EXTRA_TITLE = "title" + +class CommonDemoActivity : BaseDemoActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + val extras = intent.extras ?: return finish() + + val layout = extras.getInt(EXTRA_LAYOUT, -1) + if (layout == -1) { + finish() + return + } + val title = extras.getString(EXTRA_TITLE, "SilkFX") + window.setTitle(title) + + setContentView(R.layout.common_base) + actionBar?.title = title + LayoutInflater.from(this).inflate(layout, findViewById(R.id.demo_container), true) + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt new file mode 100644 index 000000000000..3d989a54cf27 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/app/WindowObserver.kt @@ -0,0 +1,23 @@ +/* + * 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.test.silkfx.app + +import android.view.Window + +interface WindowObserver { + fun setWindow(window: Window) +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt new file mode 100644 index 000000000000..4b85953a24b9 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/common/BaseDrawingView.kt @@ -0,0 +1,43 @@ +/* + * 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.test.silkfx.common + +import android.content.Context +import android.graphics.Color +import android.graphics.ColorSpace +import android.util.AttributeSet +import android.view.View + +open class BaseDrawingView : View { + val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB) + val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020) + val lab = ColorSpace.get(ColorSpace.Named.CIE_LAB) + + val density: Float + val dp: Int.() -> Float + + fun color(red: Float, green: Float, blue: Float, alpha: Float = 1f): Long { + return Color.pack(red, green, blue, alpha, scRGB) + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + setWillNotDraw(false) + isClickable = true + density = resources.displayMetrics.density + dp = { this * density } + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt new file mode 100644 index 000000000000..9b15b0445642 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt @@ -0,0 +1,122 @@ +/* + * 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.test.silkfx.common + +import android.content.Context +import android.content.pm.ActivityInfo +import android.hardware.display.DisplayManager +import android.util.AttributeSet +import android.view.Window +import android.widget.Button +import android.widget.LinearLayout +import android.widget.TextView +import com.android.test.silkfx.R +import com.android.test.silkfx.app.WindowObserver + +class ColorModeControls : LinearLayout, WindowObserver { + private val COLOR_MODE_HDR10 = 3 + private val SDR_WHITE_POINTS = floatArrayOf(200f, 250f, 300f, 350f, 400f, 100f, 150f) + + constructor(context: Context) : this(context, null) + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + displayManager = context.getSystemService(DisplayManager::class.java)!! + } + + private var window: Window? = null + private var currentModeDisplay: TextView? = null + private val displayManager: DisplayManager + private var targetSdrWhitePointIndex = 0 + + private val whitePoint get() = SDR_WHITE_POINTS[targetSdrWhitePointIndex] + + override fun onFinishInflate() { + super.onFinishInflate() + val window = window ?: throw IllegalStateException("Failed to attach window") + + currentModeDisplay = findViewById(R.id.current_mode)!! + setColorMode(window.colorMode) + + findViewById<Button>(R.id.mode_default)!!.setOnClickListener { + setColorMode(ActivityInfo.COLOR_MODE_DEFAULT) + } + findViewById<Button>(R.id.mode_wide)!!.setOnClickListener { + setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT) + } + findViewById<Button>(R.id.mode_hdr)!!.setOnClickListener { + setColorMode(ActivityInfo.COLOR_MODE_HDR) + } + findViewById<Button>(R.id.mode_hdr10)!!.setOnClickListener { + setColorMode(COLOR_MODE_HDR10) + } + } + + private fun setColorMode(newMode: Int) { + val window = window!! + var sdrWhitepointChanged = false + // Need to do this before setting the colorMode, as setting the colorMode will + // trigger the attribute change listener + if (newMode == ActivityInfo.COLOR_MODE_HDR || + newMode == COLOR_MODE_HDR10) { + if (window.colorMode == newMode) { + targetSdrWhitePointIndex = (targetSdrWhitePointIndex + 1) % SDR_WHITE_POINTS.size + sdrWhitepointChanged = true + } + setBrightness(1.0f) + } else { + setBrightness(.4f) + } + window.colorMode = newMode + if (sdrWhitepointChanged) { + threadedRenderer?.setColorMode(newMode, whitePoint) + } + val whitePoint = whitePoint.toInt() + currentModeDisplay?.run { + text = "Current Mode: " + when (newMode) { + ActivityInfo.COLOR_MODE_DEFAULT -> "Default/SRGB" + ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT -> "Wide Gamut" + ActivityInfo.COLOR_MODE_HDR -> "HDR (sdr white point $whitePoint)" + COLOR_MODE_HDR10 -> "HDR10 (sdr white point $whitePoint)" + else -> "Unknown" + } + } + } + + override fun setWindow(window: Window) { + this.window = window + } + + private fun setBrightness(level: Float) { + // To keep window state in sync + window?.attributes?.screenBrightness = level + invalidate() + // To force an 'immediate' snap to what we want + // Imperfect, but close enough, synchronization by waiting for frame commit to set the value + viewTreeObserver.registerFrameCommitCallback { + try { + displayManager.setTemporaryBrightness(level) + } catch (ex: Exception) { + // Ignore a permission denied rejection - it doesn't meaningfully change much + } + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + threadedRenderer?.setColorMode(window!!.colorMode, whitePoint) + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt new file mode 100644 index 000000000000..f42161f63811 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/common/HDRIndicator.kt @@ -0,0 +1,50 @@ +/* + * 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.test.silkfx.common + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.ColorSpace +import android.graphics.Paint +import android.graphics.RectF +import android.util.AttributeSet +import android.view.View + +class HDRIndicator(context: Context) : View(context) { + constructor(context: Context, attrs: AttributeSet?) : this(context) + + val scRGB = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB) + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + val paint = Paint() + paint.isAntiAlias = true + val rect = RectF(0f, 0f, width.toFloat(), height.toFloat()) + paint.textSize = height.toFloat() + + canvas.drawColor(Color.pack(1f, 1f, 1f, 1f, scRGB)) + + paint.setColor(Color.pack(1.1f, 1.1f, 1.1f, 1f, scRGB)) + canvas.drawText("H", rect.left, rect.bottom, paint) + paint.setColor(Color.pack(1.2f, 1.2f, 1.2f, 1f, scRGB)) + canvas.drawText("D", rect.left + height.toFloat(), rect.bottom, paint) + paint.setColor(Color.pack(1.3f, 1.3f, 1.3f, 1f, scRGB)) + canvas.drawText("R", rect.left + height.toFloat() * 2, rect.bottom, paint) + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt new file mode 100644 index 000000000000..4ad21faec9d4 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt @@ -0,0 +1,99 @@ +/* + * 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.test.silkfx.hdr + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BlendMode +import android.graphics.Canvas +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.Rect +import android.graphics.Shader +import android.graphics.drawable.BitmapDrawable +import android.util.AttributeSet +import com.android.test.silkfx.common.BaseDrawingView + +class BlingyNotification : BaseDrawingView { + + private val image: Bitmap? + private val bounds = Rect() + private val paint = Paint() + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + val typed = context.obtainStyledAttributes(attrs, intArrayOf(android.R.attr.src)) + val drawable = typed.getDrawable(0) + image = if (drawable is BitmapDrawable) { + drawable.bitmap + } else { + null + } + typed.recycle() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val image = image ?: return super.onMeasure(widthMeasureSpec, heightMeasureSpec) + + val widthMode = MeasureSpec.getMode(widthMeasureSpec) + val heightMode = MeasureSpec.getMode(heightMeasureSpec) + + // Currently only used in this mode, so that's all we'll bother to support + if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) { + val width = MeasureSpec.getSize(widthMeasureSpec) + + var height = image.height * width / image.width + if (heightMode == MeasureSpec.AT_MOST) { + height = minOf(MeasureSpec.getSize(heightMeasureSpec), height) + } + setMeasuredDimension(width, height) + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + bounds.set(0, 0, w, h) + paint.shader = LinearGradient(0f, 0f, w.toFloat(), 0f, + longArrayOf( + color(1f, 1f, 1f, 0f), + color(1f, 1f, 1f, .1f), + color(2f, 2f, 2f, .3f), + color(1f, 1f, 1f, .2f), + color(1f, 1f, 1f, 0f) + ), + floatArrayOf(.2f, .4f, .5f, .6f, .8f), + Shader.TileMode.CLAMP) + paint.blendMode = BlendMode.PLUS + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + + val image = image ?: return + + canvas.drawBitmap(image, null, bounds, null) + + canvas.save() + val frac = ((drawingTime % 2000) / 300f) - 1f + canvas.translate(width * frac, 0f) + canvas.rotate(-45f) + canvas.drawPaint(paint) + canvas.restore() + invalidate() + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt new file mode 100644 index 000000000000..64dbb22ace43 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowActivity.kt @@ -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 com.android.test.silkfx.hdr + +import android.os.Bundle +import com.android.test.silkfx.R +import com.android.test.silkfx.app.BaseDemoActivity + +class GlowActivity : BaseDemoActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.hdr_glows) + findViewById<GlowingCard>(R.id.card2)!!.setGlowIntensity(4f) + } +} diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt new file mode 100644 index 000000000000..b388bb659685 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/GlowingCard.kt @@ -0,0 +1,85 @@ +/* + * 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.test.silkfx.hdr + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.LinearGradient +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Shader +import android.util.AttributeSet +import com.android.test.silkfx.common.BaseDrawingView + +class GlowingCard : BaseDrawingView { + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + val radius: Float + var COLOR_MAXIMIZER = 1f + + init { + radius = 10.dp() + } + + fun setGlowIntensity(multiplier: Float) { + COLOR_MAXIMIZER = multiplier + invalidate() + } + + override fun setPressed(pressed: Boolean) { + super.setPressed(pressed) + invalidate() + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val paint = Paint() + paint.isAntiAlias = true + val rect = RectF(0f, 0f, width.toFloat(), height.toFloat()) + val glowColor = Color.pack(.5f * COLOR_MAXIMIZER, .4f * COLOR_MAXIMIZER, + .75f * COLOR_MAXIMIZER, 1f, scRGB) + + if (isPressed) { + paint.setColor(Color.pack(2f, 2f, 2f, 1f, scRGB)) + paint.strokeWidth = 4.dp() + paint.style = Paint.Style.FILL + paint.shader = LinearGradient(rect.left, rect.bottom, rect.right, rect.top, + glowColor, + Color.pack(0f, 0f, 0f, 0f, scRGB), + Shader.TileMode.CLAMP) + canvas.drawRoundRect(rect, radius, radius, paint) + } + + rect.inset(3.dp(), 3.dp()) + + paint.setColor(Color.pack(.14f, .14f, .14f, .8f, scRGB)) + paint.style = Paint.Style.FILL + paint.shader = null + canvas.drawRoundRect(rect, radius, radius, paint) + + rect.inset(5.dp(), 5.dp()) + paint.textSize = 14.dp() + paint.isFakeBoldText = true + + paint.color = Color.WHITE + canvas.drawText("glow = scRGB{${Color.red(glowColor)}, ${Color.green(glowColor)}, " + + "${Color.blue(glowColor)}}", rect.left, rect.centerY(), paint) + canvas.drawText("(press to activate)", rect.left, rect.bottom, paint) + } +}
\ No newline at end of file diff --git a/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt new file mode 100644 index 000000000000..599585e9d125 --- /dev/null +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/RadialGlow.kt @@ -0,0 +1,91 @@ +/* + * 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.test.silkfx.hdr + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RadialGradient +import android.graphics.RectF +import android.graphics.Shader +import android.util.AttributeSet +import com.android.test.silkfx.common.BaseDrawingView +import kotlin.math.min + +class RadialGlow : BaseDrawingView { + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) + + var glowToggle = false + + val glowColor = color(4f, 3.3f, 2.8f) + val bgColor = color(.15f, .15f, .15f) + val fgColor = color(.51f, .52f, .50f, .4f) + var glow: RadialGradient + + init { + glow = RadialGradient(0f, 0f, 100.dp(), glowColor, bgColor, Shader.TileMode.CLAMP) + isClickable = true + setOnClickListener { + glowToggle = !glowToggle + invalidate() + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + glow = RadialGradient(0f, 0f, + min(w, h).toFloat(), glowColor, bgColor, Shader.TileMode.CLAMP) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radius = 10.dp() + + val paint = Paint() + paint.isDither = true + paint.isAntiAlias = true + paint.textSize = 18.dp() + paint.textAlign = Paint.Align.CENTER + + val rect = RectF(0f, 0f, width.toFloat(), height.toFloat()) + + paint.setColor(bgColor) + canvas.drawRoundRect(rect, radius, radius, paint) + + if (glowToggle) { + paint.shader = glow + canvas.save() + val frac = (drawingTime % 5000) / 5000f + canvas.translate(rect.width() * frac, rect.height() - (rect.height() * frac)) + canvas.drawPaint(paint) + canvas.restore() + paint.shader = null + invalidate() + } + + paint.setColor(fgColor) + val innerRect = RectF(rect) + innerRect.inset(rect.width() / 4, rect.height() / 4) + canvas.drawRoundRect(innerRect, radius, radius, paint) + + paint.setColor(color(1f, 1f, 1f)) + canvas.drawText("Tap to toggle animation", rect.centerX(), innerRect.top - 4.dp(), paint) + canvas.drawText("Outside text", rect.centerX(), rect.bottom - 4.dp(), paint) + canvas.drawText("Inside text", innerRect.centerX(), innerRect.bottom - 4.dp(), paint) + } +}
\ No newline at end of file diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 4ccf79a0cb37..de1c5759ee87 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -49,6 +50,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.NotificationManager; @@ -65,6 +67,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.LinkProperties; +import android.net.LocalSocket; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; @@ -74,6 +77,7 @@ import android.net.VpnManager; import android.net.VpnService; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Process; @@ -101,13 +105,20 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.net.Inet4Address; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -133,7 +144,8 @@ public class VpnTest { managedProfileA.profileGroupId = primaryUser.id; } - static final String TEST_VPN_PKG = "com.dummy.vpn"; + static final String EGRESS_IFACE = "wlan0"; + static final String TEST_VPN_PKG = "com.testvpn.vpn"; private static final String TEST_VPN_SERVER = "1.2.3.4"; private static final String TEST_VPN_IDENTITY = "identity"; private static final byte[] TEST_VPN_PSK = "psk".getBytes(); @@ -1012,31 +1024,190 @@ public class VpnTest { // a subsequent CL. } - @Test - public void testStartLegacyVpn() throws Exception { + public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception { final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); // Dummy egress interface - final String egressIface = "DUMMY0"; final LinkProperties lp = new LinkProperties(); - lp.setInterfaceName(egressIface); + lp.setInterfaceName(EGRESS_IFACE); final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - InetAddresses.parseNumericAddress("192.0.2.0"), egressIface); + InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE); lp.addRoute(defaultRoute); - vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp); + vpn.startLegacyVpn(vpnProfile, mKeyStore, lp); + return vpn; + } + @Test + public void testStartPlatformVpn() throws Exception { + startLegacyVpn(mVpnProfile); // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in - // a subsequent CL. + // a subsequent patch. + } + + @Test + public void testStartRacoonNumericAddress() throws Exception { + startRacoon("1.2.3.4", "1.2.3.4"); + } + + @Test + public void testStartRacoonHostname() throws Exception { + startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve + } + + public void startRacoon(final String serverAddr, final String expectedAddr) + throws Exception { + final ConditionVariable legacyRunnerReady = new ConditionVariable(); + final VpnProfile profile = new VpnProfile("testProfile" /* key */); + profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK; + profile.name = "testProfileName"; + profile.username = "userName"; + profile.password = "thePassword"; + profile.server = serverAddr; + profile.ipsecIdentifier = "id"; + profile.ipsecSecret = "secret"; + profile.l2tpSecret = "l2tpsecret"; + when(mConnectivityManager.getAllNetworks()) + .thenReturn(new Network[] { new Network(101) }); + when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(), + anyInt(), any(), anyInt())).thenAnswer(invocation -> { + // The runner has registered an agent and is now ready. + legacyRunnerReady.open(); + return new Network(102); + }); + final Vpn vpn = startLegacyVpn(profile); + final TestDeps deps = (TestDeps) vpn.mDeps; + try { + // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK + assertArrayEquals( + new String[] { EGRESS_IFACE, expectedAddr, "udppsk", + profile.ipsecIdentifier, profile.ipsecSecret, "1701" }, + deps.racoonArgs.get(10, TimeUnit.SECONDS)); + // literal values are hardcoded in Vpn.java for mtpd args + assertArrayEquals( + new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret, + "name", profile.username, "password", profile.password, + "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", + "idle", "1800", "mtu", "1400", "mru", "1400" }, + deps.mtpdArgs.get(10, TimeUnit.SECONDS)); + // Now wait for the runner to be ready before testing for the route. + legacyRunnerReady.block(10_000); + // In this test the expected address is always v4 so /32 + final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"), + RouteInfo.RTN_THROW); + assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : " + + vpn.mConfig.routes, + vpn.mConfig.routes.contains(expectedRoute)); + } finally { + // Now interrupt the thread, unblock the runner and clean up. + vpn.mVpnRunner.exitVpnRunner(); + deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier + vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup + } + } + + private static final class TestDeps extends Vpn.Dependencies { + public final CompletableFuture<String[]> racoonArgs = new CompletableFuture(); + public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture(); + public final File mStateFile; + + private final HashMap<String, Boolean> mRunningServices = new HashMap<>(); + + TestDeps() { + try { + mStateFile = File.createTempFile("vpnTest", ".tmp"); + mStateFile.deleteOnExit(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void startService(final String serviceName) { + mRunningServices.put(serviceName, true); + } + + @Override + public void stopService(final String serviceName) { + mRunningServices.put(serviceName, false); + } + + @Override + public boolean isServiceRunning(final String serviceName) { + return mRunningServices.getOrDefault(serviceName, false); + } + + @Override + public boolean isServiceStopped(final String serviceName) { + return !isServiceRunning(serviceName); + } + + @Override + public File getStateFile() { + return mStateFile; + } + + @Override + public void sendArgumentsToDaemon( + final String daemon, final LocalSocket socket, final String[] arguments, + final Vpn.RetryScheduler interruptChecker) throws IOException { + if ("racoon".equals(daemon)) { + racoonArgs.complete(arguments); + } else if ("mtpd".equals(daemon)) { + writeStateFile(arguments); + mtpdArgs.complete(arguments); + } else { + throw new UnsupportedOperationException("Unsupported daemon : " + daemon); + } + } + + private void writeStateFile(final String[] arguments) throws IOException { + mStateFile.delete(); + mStateFile.createNewFile(); + mStateFile.deleteOnExit(); + final BufferedWriter writer = new BufferedWriter( + new FileWriter(mStateFile, false /* append */)); + writer.write(EGRESS_IFACE); + writer.write("\n"); + // addresses + writer.write("10.0.0.1/24\n"); + // routes + writer.write("192.168.6.0/24\n"); + // dns servers + writer.write("192.168.6.1\n"); + // search domains + writer.write("vpn.searchdomains.com\n"); + // endpoint - intentionally empty + writer.write("\n"); + writer.flush(); + writer.close(); + } + + @Override + @NonNull + public InetAddress resolve(final String endpoint) { + try { + // If a numeric IP address, return it. + return InetAddress.parseNumericAddress(endpoint); + } catch (IllegalArgumentException e) { + // Otherwise, return some token IP to test for. + return InetAddress.parseNumericAddress("5.6.7.8"); + } + } + + @Override + public boolean checkInterfacePresent(final Vpn vpn, final String iface) { + return true; + } } /** * Mock some methods of vpn object. */ private Vpn createVpn(@UserIdInt int userId) { - return new Vpn(Looper.myLooper(), mContext, mNetService, + return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService, userId, mKeyStore, mSystemServices, mIkev2SessionCreator); } diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index f9c54f645e2c..d84ca3d92f67 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -78,6 +78,8 @@ using ::android::base::StringPrintf; namespace aapt { +constexpr uint8_t kAndroidPackageId = 0x01; + class LinkContext : public IAaptContext { public: explicit LinkContext(IDiagnostics* diagnostics) @@ -1805,7 +1807,7 @@ class Linker { // Override the package ID when it is "android". if (context_->GetCompilationPackage() == "android") { - context_->SetPackageId(0x01); + context_->SetPackageId(kAndroidPackageId); // Verify we're building a regular app. if (context_->GetPackageType() != PackageType::kApp) { @@ -1862,7 +1864,8 @@ class Linker { if (context_->GetPackageType() != PackageType::kStaticLib) { PrivateAttributeMover mover; - if (!mover.Consume(context_, &final_table_)) { + if (context_->GetPackageId() == kAndroidPackageId && + !mover.Consume(context_, &final_table_)) { context_->GetDiagnostics()->Error(DiagMessage() << "failed moving private attributes"); return 1; } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 3cdfb00d288c..e4937892e2f7 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -122,7 +122,7 @@ interface IWifiManager DhcpInfo getDhcpInfo(); - void setScanAlwaysAvailable(boolean isAvailable); + void setScanAlwaysAvailable(boolean isAvailable, String packageName); boolean isScanAlwaysAvailable(); @@ -142,9 +142,9 @@ interface IWifiManager void updateInterfaceIpState(String ifaceName, int mode); - boolean startSoftAp(in WifiConfiguration wifiConfig); + boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName); - boolean startTetheredHotspot(in SoftApConfiguration softApConfig); + boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName); boolean stopSoftAp(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index ae834f929691..b28b902910bf 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2802,7 +2802,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean isAvailable) { try { - mService.setScanAlwaysAvailable(isAvailable); + mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3035,7 +3035,7 @@ public class WifiManager { }) public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) { try { - return mService.startSoftAp(wifiConfig); + return mService.startSoftAp(wifiConfig, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3059,7 +3059,7 @@ public class WifiManager { }) public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) { try { - return mService.startTetheredHotspot(softApConfig); + return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index cba1690ac635..e7f1916c9e82 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -218,10 +218,10 @@ public class WifiManagerTest { */ @Test public void testStartSoftApCallsServiceWithWifiConfig() throws Exception { - when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true); + when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startSoftAp(mApConfig)); - when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false); + when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startSoftAp(mApConfig)); } @@ -231,10 +231,10 @@ public class WifiManagerTest { */ @Test public void testStartSoftApCallsServiceWithNullConfig() throws Exception { - when(mWifiService.startSoftAp(eq(null))).thenReturn(true); + when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startSoftAp(null)); - when(mWifiService.startSoftAp(eq(null))).thenReturn(false); + when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startSoftAp(null)); } @@ -257,10 +257,12 @@ public class WifiManagerTest { @Test public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception { SoftApConfiguration softApConfig = generatorTestSoftApConfig(); - when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true); + when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME)) + .thenReturn(true); assertTrue(mWifiManager.startTetheredHotspot(softApConfig)); - when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false); + when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME)) + .thenReturn(false); assertFalse(mWifiManager.startTetheredHotspot(softApConfig)); } @@ -270,10 +272,10 @@ public class WifiManagerTest { */ @Test public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception { - when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true); + when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startTetheredHotspot(null)); - when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false); + when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startTetheredHotspot(null)); } @@ -2375,7 +2377,7 @@ public class WifiManagerTest { @Test public void testScanAvailable() throws Exception { mWifiManager.setScanAlwaysAvailable(true); - verify(mWifiService).setScanAlwaysAvailable(true); + verify(mWifiService).setScanAlwaysAvailable(true, TEST_PACKAGE_NAME); when(mWifiService.isScanAlwaysAvailable()).thenReturn(false); assertFalse(mWifiManager.isScanAlwaysAvailable()); |