diff options
395 files changed, 7886 insertions, 5034 deletions
diff --git a/Android.bp b/Android.bp index 0780f88df7c6..e756b3428164 100644 --- a/Android.bp +++ b/Android.bp @@ -1415,3 +1415,30 @@ filegroup { name: "framework-telephony-jarjar-rules", srcs: ["telephony/framework-telephony-jarjar-rules.txt"], } + +// protolog start +filegroup { + name: "protolog-common-src", + srcs: [ + "core/java/com/android/internal/protolog/common/**/*.java", + ], +} + +java_library { + name: "protolog-lib", + platform_apis: true, + srcs: [ + "core/java/com/android/internal/protolog/ProtoLogImpl.java", + "core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java", + ":protolog-common-src", + ], +} + +java_library { + name: "protolog-groups", + srcs: [ + "core/java/com/android/internal/protolog/ProtoLogGroup.java", + ":protolog-common-src", + ], +} +// protolog end diff --git a/api/current.txt b/api/current.txt index b70103b931d4..17fbb55d2f91 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24065,6 +24065,8 @@ package android.media { method public boolean isSink(); method public boolean isSource(); field public static final int TYPE_AUX_LINE = 19; // 0x13 + field public static final int TYPE_BLE_HEADSET = 26; // 0x1a + field public static final int TYPE_BLE_SPEAKER = 27; // 0x1b field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 field public static final int TYPE_BLUETOOTH_SCO = 7; // 0x7 field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1 diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index f53ac8c895ce..b587ea1f3b74 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -94,6 +94,7 @@ package android.os { } public interface Parcelable { + method public default int getStability(); field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0 field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1 } diff --git a/api/system-current.txt b/api/system-current.txt index c15c2a817adb..b011e9af40a0 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -10491,7 +10491,7 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle); method @Deprecated public android.content.ComponentName getDefaultPhoneApp(); - method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); + method @Deprecated public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index a6c402ccc075..15e22a3410cf 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -166,7 +166,7 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, Status Idmap2Service::createIdmap(const std::string& target_apk_path, const std::string& overlay_apk_path, int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, - aidl::nullable<std::string>* _aidl_return) { + std::optional<std::string>* _aidl_return) { assert(_aidl_return); SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path; _aidl_return->reset(); @@ -214,7 +214,7 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, return error("failed to write to idmap path " + idmap_path); } - *_aidl_return = aidl::make_nullable<std::string>(idmap_path); + *_aidl_return = idmap_path; return ok(); } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h index ea931c936b0e..1a445192aff8 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.h +++ b/cmds/idmap2/idmap2d/Idmap2Service.h @@ -21,7 +21,6 @@ #include <android-base/unique_fd.h> #include <binder/BinderService.h> -#include <binder/Nullable.h> #include "android/os/BnIdmap2.h" @@ -47,7 +46,7 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 { binder::Status createIdmap(const std::string& target_apk_path, const std::string& overlay_apk_path, int32_t fulfilled_policies, bool enforce_overlayable, int32_t user_id, - aidl::nullable<std::string>* _aidl_return) override; + std::optional<std::string>* _aidl_return) override; private: // Cache the crc of the android framework package since the crc cannot change without a reboot. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 7a4f11d0de4d..7cec717f96e0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -5128,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 @@ -5370,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); @@ -5645,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) { @@ -5702,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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index b40dd0053846..95136bb46339 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2657,8 +2657,10 @@ public class AppOpsManager { * @hide */ // TODO: this should probably be @SystemApi as well - public static @NonNull String toReceiverId(@NonNull Object obj) { - if (obj instanceof PendingIntent) { + public static @NonNull String toReceiverId(@Nullable Object obj) { + if (obj == null) { + return "null"; + } else if (obj instanceof PendingIntent) { return toReceiverId((PendingIntent) obj); } else { return obj.getClass().getName() + "@" + System.identityHashCode(obj); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 9613e58fb943..f6b533434ac2 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1624,8 +1624,9 @@ class ContextImpl extends Context { } try { final Intent intent = ActivityManager.getService().registerReceiverWithFeature( - mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd, - filter, broadcastPermission, userId, flags); + mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), + AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId, + flags); if (intent != null) { intent.setExtrasClassLoader(getClassLoader()); intent.prepareToEnterProcess(); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 99640118ccdf..93dfc79109a6 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -123,8 +123,8 @@ interface IActivityManager { in IIntentReceiver receiver, in IntentFilter filter, in String requiredPermission, int userId, int flags); Intent registerReceiverWithFeature(in IApplicationThread caller, in String callerPackage, - in String callingFeatureId, in IIntentReceiver receiver, in IntentFilter filter, - in String requiredPermission, int userId, int flags); + in String callingFeatureId, in String receiverId, in IIntentReceiver receiver, + in IntentFilter filter, in String requiredPermission, int userId, int flags); @UnsupportedAppUsage void unregisterReceiver(in IIntentReceiver receiver); /** @deprecated Use {@link #broadcastIntentWithFeature} instead */ diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index 8c3180b400ef..4c9e400681ee 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -39,7 +39,7 @@ interface IUiAutomationConnection { boolean injectInputEvent(in InputEvent event, boolean sync); void syncInputTransactions(); boolean setRotation(int rotation); - Bitmap takeScreenshot(in Rect crop, int rotation); + Bitmap takeScreenshot(in Rect crop); boolean clearWindowContentFrameStats(int windowId); WindowContentFrameStats getWindowContentFrameStats(int windowId); void clearWindowAnimationFrameStats(); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 747789901b9d..fb2120e5a35b 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -39,7 +39,6 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.Log; -import android.util.LruCache; import android.util.Pair; import android.util.Slog; import android.view.Display; @@ -62,7 +61,6 @@ import java.util.List; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Consumer; -import java.util.function.Predicate; /** @hide */ public class ResourcesManager { @@ -129,17 +127,30 @@ public class ResourcesManager { } } - private static final boolean ENABLE_APK_ASSETS_CACHE = false; - /** - * The ApkAssets we are caching and intend to hold strong references to. + * Loads {@link ApkAssets} and caches them to prevent their garbage collection while the + * instance is alive and reachable. */ - private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = - (ENABLE_APK_ASSETS_CACHE) ? new LruCache<>(3) : null; + private class ApkAssetsSupplier { + final ArrayMap<ApkKey, ApkAssets> mLocalCache = new ArrayMap<>(); + + /** + * Retrieves the {@link ApkAssets} corresponding to the specified key, caches the ApkAssets + * within this instance, and inserts the loaded ApkAssets into the {@link #mCachedApkAssets} + * cache. + */ + ApkAssets load(final ApkKey apkKey) throws IOException { + ApkAssets apkAssets = mLocalCache.get(apkKey); + if (apkAssets == null) { + apkAssets = loadApkAssets(apkKey); + mLocalCache.put(apkKey, apkAssets); + } + return apkAssets; + } + } /** - * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't - * in our LRU cache. Bonus resources :) + * The ApkAssets that are being referenced in the wild that we can reuse. */ private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>(); @@ -228,7 +239,8 @@ public class ResourcesManager { } } - DisplayMetrics getDisplayMetrics() { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public DisplayMetrics getDisplayMetrics() { return getDisplayMetrics(Display.DEFAULT_DISPLAY, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS); } @@ -337,113 +349,116 @@ public class ResourcesManager { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } - private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay) - throws IOException { - final ApkKey newKey = new ApkKey(path, sharedLib, overlay); - ApkAssets apkAssets = null; - if (mLoadedApkAssets != null) { - apkAssets = mLoadedApkAssets.get(newKey); - if (apkAssets != null && apkAssets.isUpToDate()) { - return apkAssets; - } - } + private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { + ApkAssets apkAssets; // Optimistically check if this ApkAssets exists somewhere else. - final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey); - if (apkAssetsRef != null) { - apkAssets = apkAssetsRef.get(); - if (apkAssets != null && apkAssets.isUpToDate()) { - if (mLoadedApkAssets != null) { - mLoadedApkAssets.put(newKey, apkAssets); + synchronized (this) { + final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(key); + if (apkAssetsRef != null) { + apkAssets = apkAssetsRef.get(); + if (apkAssets != null && apkAssets.isUpToDate()) { + return apkAssets; + } else { + // Clean up the reference. + mCachedApkAssets.remove(key); } - - return apkAssets; - } else { - // Clean up the reference. - mCachedApkAssets.remove(newKey); } } // We must load this from disk. - if (overlay) { - apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(path), 0 /*flags*/); + if (key.overlay) { + apkAssets = ApkAssets.loadOverlayFromPath(overlayPathToIdmapPath(key.path), + 0 /*flags*/); } else { - apkAssets = ApkAssets.loadFromPath(path, sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); + apkAssets = ApkAssets.loadFromPath(key.path, + key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0); } - if (mLoadedApkAssets != null) { - mLoadedApkAssets.put(newKey, apkAssets); + synchronized (this) { + mCachedApkAssets.put(key, new WeakReference<>(apkAssets)); } - mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets)); return apkAssets; } /** - * Creates an AssetManager from the paths within the ResourcesKey. - * - * This can be overridden in tests so as to avoid creating a real AssetManager with - * real APK paths. - * @param key The key containing the resource paths to add to the AssetManager. - * @return a new AssetManager. - */ - @VisibleForTesting - @UnsupportedAppUsage - protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { - final AssetManager.Builder builder = new AssetManager.Builder(); + * Retrieves a list of apk keys representing the ApkAssets that should be loaded for + * AssetManagers mapped to the {@param key}. + */ + private static @NonNull ArrayList<ApkKey> extractApkKeys(@NonNull final ResourcesKey key) { + final ArrayList<ApkKey> apkKeys = new ArrayList<>(); // resDir can be null if the 'android' package is creating a new Resources object. // This is fine, since each AssetManager automatically loads the 'android' package // already. if (key.mResDir != null) { - try { - builder.addApkAssets(loadApkAssets(key.mResDir, false /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.e(TAG, "failed to add asset path " + key.mResDir); - return null; - } + apkKeys.add(new ApkKey(key.mResDir, false /*sharedLib*/, false /*overlay*/)); } if (key.mSplitResDirs != null) { for (final String splitResDir : key.mSplitResDirs) { - try { - builder.addApkAssets(loadApkAssets(splitResDir, false /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.e(TAG, "failed to add split asset path " + splitResDir); - return null; - } + apkKeys.add(new ApkKey(splitResDir, false /*sharedLib*/, false /*overlay*/)); } } if (key.mLibDirs != null) { for (final String libDir : key.mLibDirs) { + // Avoid opening files we know do not have resources, like code-only .jar files. if (libDir.endsWith(".apk")) { - // Avoid opening files we know do not have resources, - // like code-only .jar files. - try { - builder.addApkAssets(loadApkAssets(libDir, true /*sharedLib*/, - false /*overlay*/)); - } catch (IOException e) { - Log.w(TAG, "Asset path '" + libDir + - "' does not exist or contains no resources."); - - // continue. - } + apkKeys.add(new ApkKey(libDir, true /*sharedLib*/, false /*overlay*/)); } } } if (key.mOverlayDirs != null) { for (final String idmapPath : key.mOverlayDirs) { - try { - builder.addApkAssets(loadApkAssets(idmapPath, false /*sharedLib*/, - true /*overlay*/)); - } catch (IOException e) { - Log.w(TAG, "failed to add overlay path " + idmapPath); + apkKeys.add(new ApkKey(idmapPath, false /*sharedLib*/, true /*overlay*/)); + } + } + + return apkKeys; + } + + /** + * Creates an AssetManager from the paths within the ResourcesKey. + * + * This can be overridden in tests so as to avoid creating a real AssetManager with + * real APK paths. + * @param key The key containing the resource paths to add to the AssetManager. + * @return a new AssetManager. + */ + @VisibleForTesting + @UnsupportedAppUsage + protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) { + return createAssetManager(key, /* apkSupplier */ null); + } + + /** + * Variant of {@link #createAssetManager(ResourcesKey)} that attempts to load ApkAssets + * from an {@link ApkAssetsSupplier} if non-null; otherwise ApkAssets are loaded using + * {@link #loadApkAssets(ApkKey)}. + */ + private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key, + @Nullable ApkAssetsSupplier apkSupplier) { + final AssetManager.Builder builder = new AssetManager.Builder(); - // continue. + final ArrayList<ApkKey> apkKeys = extractApkKeys(key); + for (int i = 0, n = apkKeys.size(); i < n; i++) { + final ApkKey apkKey = apkKeys.get(i); + try { + builder.addApkAssets( + (apkSupplier != null) ? apkSupplier.load(apkKey) : loadApkAssets(apkKey)); + } catch (IOException e) { + if (apkKey.overlay) { + Log.w(TAG, String.format("failed to add overlay path '%s'", apkKey.path), e); + } else if (apkKey.sharedLib) { + Log.w(TAG, String.format( + "asset path '%s' does not exist or contains no resources", + apkKey.path), e); + } else { + Log.e(TAG, String.format("failed to add asset path '%s'", apkKey.path), e); + return null; } } } @@ -480,24 +495,6 @@ public class ResourcesManager { pw.println("ResourcesManager:"); pw.increaseIndent(); - if (mLoadedApkAssets != null) { - pw.print("cached apks: total="); - pw.print(mLoadedApkAssets.size()); - pw.print(" created="); - pw.print(mLoadedApkAssets.createCount()); - pw.print(" evicted="); - pw.print(mLoadedApkAssets.evictionCount()); - pw.print(" hit="); - pw.print(mLoadedApkAssets.hitCount()); - pw.print(" miss="); - pw.print(mLoadedApkAssets.missCount()); - pw.print(" max="); - pw.print(mLoadedApkAssets.maxSize()); - } else { - pw.print("cached apks: 0 [cache disabled]"); - } - pw.println(); - pw.print("total apks: "); pw.println(countLiveReferences(mCachedApkAssets.values())); @@ -533,11 +530,12 @@ public class ResourcesManager { return config; } - private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key) { + private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key, + @Nullable ApkAssetsSupplier apkSupplier) { final DisplayAdjustments daj = new DisplayAdjustments(key.mOverrideConfiguration); daj.setCompatibilityInfo(key.mCompatInfo); - final AssetManager assets = createAssetManager(key); + final AssetManager assets = createAssetManager(key, apkSupplier); if (assets == null) { return null; } @@ -575,9 +573,18 @@ public class ResourcesManager { */ private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( @NonNull ResourcesKey key) { + return findOrCreateResourcesImplForKeyLocked(key, /* apkSupplier */ null); + } + + /** + * Variant of {@link #findOrCreateResourcesImplForKeyLocked(ResourcesKey)} that attempts to + * load ApkAssets from a {@link ApkAssetsSupplier} when creating a new ResourcesImpl. + */ + private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( + @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) { ResourcesImpl impl = findResourcesImplForKeyLocked(key); if (impl == null) { - impl = createResourcesImpl(key); + impl = createResourcesImpl(key, apkSupplier); if (impl != null) { mResourceImpls.put(key, new WeakReference<>(impl)); } @@ -766,7 +773,7 @@ public class ResourcesManager { } // Now request an actual Resources object. - return createResources(token, key, classLoader); + return createResources(token, key, classLoader, /* apkSupplier */ null); } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } @@ -810,18 +817,50 @@ public class ResourcesManager { } /** + * Creates an {@link ApkAssetsSupplier} and loads all the ApkAssets required by the {@param key} + * into the supplier. This should be done while the lock is not held to prevent performing I/O + * while holding the lock. + */ + private @NonNull ApkAssetsSupplier createApkAssetsSupplierNotLocked(@NonNull ResourcesKey key) { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#createApkAssetsSupplierNotLocked"); + try { + if (Thread.holdsLock(this)) { + Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + + " is holding mLock", new Throwable()); + } + + final ApkAssetsSupplier supplier = new ApkAssetsSupplier(); + final ArrayList<ApkKey> apkKeys = extractApkKeys(key); + for (int i = 0, n = apkKeys.size(); i < n; i++) { + final ApkKey apkKey = apkKeys.get(i); + try { + supplier.load(apkKey); + } catch (IOException e) { + Log.w(TAG, String.format("failed to preload asset path '%s'", apkKey.path), e); + } + } + return supplier; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } + } + + /** * Creates a Resources object set with a ResourcesImpl object matching the given key. * * @param activityToken The Activity this Resources object should be associated with. * @param key The key describing the parameters of the ResourcesImpl object. * @param classLoader The classloader to use for the Resources object. * If null, {@link ClassLoader#getSystemClassLoader()} is used. + * @param apkSupplier The apk assets supplier to use when creating a new ResourcesImpl object. * @return A Resources object that gets updated when * {@link #applyConfigurationToResourcesLocked(Configuration, CompatibilityInfo)} * is called. */ private @Nullable Resources createResources(@Nullable IBinder activityToken, - @NonNull ResourcesKey key, @NonNull ClassLoader classLoader) { + @NonNull ResourcesKey key, @NonNull ClassLoader classLoader, + @Nullable ApkAssetsSupplier apkSupplier) { synchronized (this) { if (DEBUG) { Throwable here = new Throwable(); @@ -829,7 +868,7 @@ public class ResourcesManager { Slog.w(TAG, "!! Get resources for activity=" + activityToken + " key=" + key, here); } - ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key); + ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier); if (resourcesImpl == null) { return null; } @@ -898,7 +937,10 @@ public class ResourcesManager { rebaseKeyForActivity(activityToken, key); } - return createResources(activityToken, key, classLoader); + // Preload the ApkAssets required by the key to prevent performing heavy I/O while the + // ResourcesManager lock is held. + final ApkAssetsSupplier assetsSupplier = createApkAssetsSupplierNotLocked(key); + return createResources(activityToken, key, classLoader, assetsSupplier); } finally { Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } @@ -969,7 +1011,13 @@ public class ResourcesManager { final ResourcesKey newKey = rebaseActivityOverrideConfig(resources, oldConfig, overrideConfig, displayId); if (newKey != null) { - updateActivityResources(resources, newKey, false); + final ResourcesImpl resourcesImpl = + findOrCreateResourcesImplForKeyLocked(newKey); + if (resourcesImpl != null && resourcesImpl != resources.getImpl()) { + // Set the ResourcesImpl, updating it for all users of this Resources + // object. + resources.setImpl(resourcesImpl); + } } } } @@ -1024,24 +1072,6 @@ public class ResourcesManager { return newKey; } - private void updateActivityResources(Resources resources, ResourcesKey newKey, - boolean hasLoader) { - final ResourcesImpl resourcesImpl; - - if (hasLoader) { - // Loaders always get new Impls because they cannot be shared - resourcesImpl = createResourcesImpl(newKey); - } else { - resourcesImpl = findOrCreateResourcesImplForKeyLocked(newKey); - } - - if (resourcesImpl != null && resourcesImpl != resources.getImpl()) { - // Set the ResourcesImpl, updating it for all users of this Resources - // object. - resources.setImpl(resourcesImpl); - } - } - public final boolean applyConfigurationToResources(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { synchronized(this) { diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index e0951bf3f4d2..109205fadf18 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -903,7 +903,7 @@ public final class UiAutomation { try { // Calling out without a lock held. screenShot = mUiAutomationConnection.takeScreenshot( - new Rect(0, 0, displaySize.x, displaySize.y), rotation); + new Rect(0, 0, displaySize.x, displaySize.y)); if (screenShot == null) { return null; } diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index ce51dba76780..70d520176ca1 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -180,7 +180,7 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } @Override - public Bitmap takeScreenshot(Rect crop, int rotation) { + public Bitmap takeScreenshot(Rect crop) { synchronized (mLock) { throwIfCalledByNotTrustedUidLocked(); throwIfShutdownLocked(); @@ -190,7 +190,15 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { try { int width = crop.width(); int height = crop.height(); - return SurfaceControl.screenshot(crop, width, height, rotation); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setSourceCrop(crop) + .setSize(width, height) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + return screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java index 283cea00b192..98e71f07407e 100644 --- a/core/java/android/content/LocusId.java +++ b/core/java/android/content/LocusId.java @@ -33,7 +33,7 @@ import java.io.PrintWriter; * by the Android System to correlate state between different subsystems such as content capture, * shortcuts, and notifications. * - * <p>For example, if your app provides an activiy representing a chat between 2 users + * <p>For example, if your app provides an activity representing a chat between 2 users * (say {@code A} and {@code B}, this chat state could be represented by: * * <pre><code> diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index cb93cbfcbfc9..fcbe36246273 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.util.TypedValue; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import dalvik.annotation.optimization.FastNative; @@ -38,7 +39,8 @@ import java.io.Reader; * * {@hide} */ -final class XmlBlock implements AutoCloseable { +@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +public final class XmlBlock implements AutoCloseable { private static final boolean DEBUG=false; @UnsupportedAppUsage @@ -88,7 +90,8 @@ final class XmlBlock implements AutoCloseable { } } - /*package*/ final class Parser implements XmlResourceParser { + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public final class Parser implements XmlResourceParser { Parser(long parseState, XmlBlock block) { mParseState = parseState; mBlock = block; 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/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index 885d137dd2fe..19cb13c7e114 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -1073,12 +1073,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan /** * @hide */ - public abstract static class GenerateChallengeCallback { - public abstract void onGenerateChallengeResult(long challenge); + public interface GenerateChallengeCallback { + void onGenerateChallengeResult(long challenge); } private abstract static class InternalGenerateChallengeCallback - extends GenerateChallengeCallback {} + implements GenerateChallengeCallback {} private class OnEnrollCancelListener implements OnCancelListener { @Override diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index e384da7574ad..71598eb6394f 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -377,12 +377,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * @hide */ - public abstract static class GenerateChallengeCallback { - public abstract void onChallengeGenerated(long challenge); + public interface GenerateChallengeCallback { + void onChallengeGenerated(long challenge); } private abstract static class InternalGenerateChallengeCallback - extends GenerateChallengeCallback {} + implements GenerateChallengeCallback {} /** * Request authentication of a crypto object. This call warms up the fingerprint hardware @@ -581,37 +581,6 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing } /** - * Same as {@link #generateChallenge(GenerateChallengeCallback)}, except blocks until the - * TEE/hardware operation is complete. - * @return challenge generated in the TEE/hardware - * @hide - */ - @RequiresPermission(MANAGE_FINGERPRINT) - public long generateChallengeBlocking() { - final AtomicReference<Long> result = new AtomicReference<>(); - final CountDownLatch latch = new CountDownLatch(1); - final GenerateChallengeCallback callback = new InternalGenerateChallengeCallback() { - @Override - public void onChallengeGenerated(long challenge) { - result.set(challenge); - latch.countDown(); - } - }; - - generateChallenge(callback); - - try { - latch.await(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Slog.e(TAG, "Interrupted while generatingChallenge", e); - e.printStackTrace(); - } - - return result.get(); - } - - - /** * Generates a unique random challenge in the TEE. A typical use case is to have it wrapped in a * HardwareAuthenticationToken, minted by Gatekeeper upon PIN/Pattern/Password verification. * The HardwareAuthenticationToken can then be sent to the biometric HAL together with a diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 0cce19222d27..8f8d451bbe8e 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -287,8 +287,8 @@ interface INetworkManagementService /** * Control network activity of a UID over interfaces with a quota limit. */ - void setUidMeteredNetworkBlacklist(int uid, boolean enable); - void setUidMeteredNetworkWhitelist(int uid, boolean enable); + void setUidMeteredNetworkDenylist(int uid, boolean enable); + void setUidMeteredNetworkAllowlist(int uid, boolean enable); boolean setDataSaverModeEnabled(boolean enable); void setUidCleartextNetworkPolicy(int uid, int policy); diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java index 3d3759e695e0..f14f66b07630 100644 --- a/core/java/android/os/Parcelable.java +++ b/core/java/android/os/Parcelable.java @@ -161,6 +161,7 @@ public interface Parcelable { * @return true if this parcelable is stable. * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) default @Stability int getStability() { return PARCELABLE_STABILITY_LOCAL; } 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/os/SystemClock.java b/core/java/android/os/SystemClock.java index fd68c2b9b5fd..26f3af0c68bb 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -178,6 +178,15 @@ public final class SystemClock { native public static long uptimeMillis(); /** + * Returns nanoseconds since boot, not counting time spent in deep sleep. + * + * @return nanoseconds of non-sleep uptime since boot. + * @hide + */ + @CriticalNative + public static native long uptimeNanos(); + + /** * Return {@link Clock} that starts at system boot, not counting time spent * in deep sleep. * diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 2ce993dfedca..6ef086b55c41 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -22,8 +22,6 @@ import static android.graphics.Matrix.MSKEW_X; import static android.graphics.Matrix.MSKEW_Y; import static android.graphics.Matrix.MTRANS_X; import static android.graphics.Matrix.MTRANS_Y; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; import static android.view.SurfaceControlProto.HASH_CODE; import static android.view.SurfaceControlProto.NAME; @@ -590,6 +588,26 @@ public final class SurfaceControl implements Parcelable { public boolean containsSecureLayers() { return mContainsSecureLayers; } + + /** + * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it. + * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap + * into + * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)} + * + * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to + * directly + * use the {@link HardwareBuffer} directly. + * + * @return Bitmap generated from the {@link HardwareBuffer} + */ + public Bitmap asBitmap() { + if (mHardwareBuffer == null) { + Log.w(TAG, "Failed to take screenshot. Null screenshot object"); + return null; + } + return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace); + } } /** @@ -597,7 +615,7 @@ public final class SurfaceControl implements Parcelable { * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs} * @hide */ - public abstract static class CaptureArgs { + private abstract static class CaptureArgs { private final int mPixelFormat; private final Rect mSourceCrop = new Rect(); private final float mFrameScale; @@ -615,7 +633,7 @@ public final class SurfaceControl implements Parcelable { * * @param <T> A builder that extends {@link Builder} */ - public abstract static class Builder<T extends Builder<T>> { + abstract static class Builder<T extends Builder<T>> { private int mPixelFormat = PixelFormat.RGBA_8888; private final Rect mSourceCrop = new Rect(); private float mFrameScale = 1; @@ -675,7 +693,6 @@ public final class SurfaceControl implements Parcelable { private final int mWidth; private final int mHeight; private final boolean mUseIdentityTransform; - private final int mRotation; private DisplayCaptureArgs(Builder builder) { super(builder); @@ -683,7 +700,6 @@ public final class SurfaceControl implements Parcelable { mWidth = builder.mWidth; mHeight = builder.mHeight; mUseIdentityTransform = builder.mUseIdentityTransform; - mRotation = builder.mRotation; } /** @@ -694,7 +710,6 @@ public final class SurfaceControl implements Parcelable { private int mWidth; private int mHeight; private boolean mUseIdentityTransform; - private @Surface.Rotation int mRotation = Surface.ROTATION_0; /** * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder @@ -736,26 +751,16 @@ public final class SurfaceControl implements Parcelable { } /** - * Replace whatever transformation (rotation, scaling, translation) the surface - * layers are currently using with the identity transformation while taking the - * screenshot. + * Replace the rotation transform of the display with the identity transformation while + * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0 + * orientation. Set this value to false if the screenshot should be taken in the + * current screen orientation. */ public Builder setUseIdentityTransform(boolean useIdentityTransform) { mUseIdentityTransform = useIdentityTransform; return this; } - /** - * Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take screenshots in its - * native portrait orientation by default, so this is useful for returning screenshots - * that are independent of device orientation. - */ - public Builder setRotation(@Surface.Rotation int rotation) { - mRotation = rotation; - return this; - } - @Override Builder getThis() { return this; @@ -2221,130 +2226,16 @@ public final class SurfaceControl implements Parcelable { } /** - * @see SurfaceControl#screenshot(Rect, int, int, boolean, int)} - * @hide - */ - @UnsupportedAppUsage - public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) { - return screenshot(sourceCrop, width, height, false, rotation); - } - - /** - * Copy the current screen contents into a hardware bitmap and return it. - * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into - * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)} + * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with + * the content. * - * CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use - * unless absolutely necessary; prefer the versions that use a {@link HardwareBuffer} such as - * {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}. - * - * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)} * @hide */ - @UnsupportedAppUsage - public static Bitmap screenshot(Rect sourceCrop, int width, int height, - boolean useIdentityTransform, int rotation) { - // TODO: should take the display as a parameter - final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); - if (displayToken == null) { - Log.w(TAG, "Failed to take screenshot because internal display is disconnected"); - return null; - } - - if (rotation == ROTATION_90 || rotation == ROTATION_270) { - rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90; - } - - SurfaceControl.rotateCropForSF(sourceCrop, rotation); - final ScreenshotHardwareBuffer buffer = screenshotToBuffer(displayToken, sourceCrop, width, - height, useIdentityTransform, rotation); - - if (buffer == null) { - Log.w(TAG, "Failed to take screenshot"); - return null; - } - return Bitmap.wrapHardwareBuffer(buffer.getHardwareBuffer(), buffer.getColorSpace()); - } - - /** - * Captures all the surfaces in a display and returns a {@link HardwareBuffer} with the content. - * - * @param display The display to take the screenshot of. - * @param sourceCrop The portion of the screen to capture into the Bitmap; caller may - * pass in 'new Rect()' if no cropping is desired. - * @param width The desired width of the returned bitmap; the raw screen will be - * scaled down to this size; caller may pass in 0 if no scaling is - * desired. - * @param height The desired height of the returned bitmap; the raw screen will - * be scaled down to this size; caller may pass in 0 if no scaling - * is desired. - * @param useIdentityTransform Replace whatever transformation (rotation, scaling, translation) - * the surface layers are currently using with the identity - * transformation while taking the screenshot. - * @param rotation Apply a custom clockwise rotation to the screenshot, i.e. - * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take - * screenshots in its native portrait orientation by default, so - * this is useful for returning screenshots that are independent of - * device orientation. - * @return Returns a HardwareBuffer that contains the captured content. - * @hide - */ - public static ScreenshotHardwareBuffer screenshotToBuffer(IBinder display, Rect sourceCrop, - int width, int height, boolean useIdentityTransform, int rotation) { - if (display == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display) - .setSourceCrop(sourceCrop) - .setSize(width, height) - .setUseIdentityTransform(useIdentityTransform) - .setRotation(rotation) - .build(); - + public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) { return nativeCaptureDisplay(captureArgs); } /** - * Like screenshotToBuffer, but if the caller is AID_SYSTEM, allows - * for the capture of secure layers. This is used for the screen rotation - * animation where the system server takes screenshots but does - * not persist them or allow them to leave the server. However in other - * cases in the system server, we mostly want to omit secure layers - * like when we take a screenshot on behalf of the assistant. - * - * @hide - */ - public static ScreenshotHardwareBuffer screenshotToBufferWithSecureLayersUnsafe(IBinder display, - Rect sourceCrop, int width, int height, boolean useIdentityTransform, - int rotation) { - if (display == null) { - throw new IllegalArgumentException("displayToken must not be null"); - } - - DisplayCaptureArgs captureArgs = new DisplayCaptureArgs.Builder(display) - .setSourceCrop(sourceCrop) - .setSize(width, height) - .setUseIdentityTransform(useIdentityTransform) - .setRotation(rotation) - .setCaptureSecureLayers(true) - .build(); - - return nativeCaptureDisplay(captureArgs); - } - - private static void rotateCropForSF(Rect crop, int rot) { - if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { - int tmp = crop.top; - crop.top = crop.left; - crop.left = tmp; - tmp = crop.right; - crop.right = crop.bottom; - crop.bottom = tmp; - } - } - - /** * Captures a layer and its children and returns a {@link HardwareBuffer} with the content. * * @param layer The root layer to capture. diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java index fed3dbf8f49c..00086587819f 100644 --- a/core/java/android/view/textclassifier/TextClassificationSession.java +++ b/core/java/android/view/textclassifier/TextClassificationSession.java @@ -20,9 +20,11 @@ import android.annotation.NonNull; import android.annotation.WorkerThread; import android.view.textclassifier.SelectionEvent.InvocationMethod; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.util.Objects; +import java.util.function.Supplier; import sun.misc.Cleaner; @@ -40,6 +42,9 @@ final class TextClassificationSession implements TextClassifier { private final TextClassificationContext mClassificationContext; private final Cleaner mCleaner; + private final Object mLock = new Object(); + + @GuardedBy("mLock") private boolean mDestroyed; TextClassificationSession(TextClassificationContext context, TextClassifier delegate) { @@ -54,8 +59,7 @@ final class TextClassificationSession implements TextClassifier { @Override public TextSelection suggestSelection(TextSelection.Request request) { - checkDestroyed(); - return mDelegate.suggestSelection(request); + return checkDestroyedAndRun(() -> mDelegate.suggestSelection(request)); } private void initializeRemoteSession() { @@ -67,77 +71,97 @@ final class TextClassificationSession implements TextClassifier { @Override public TextClassification classifyText(TextClassification.Request request) { - checkDestroyed(); - return mDelegate.classifyText(request); + return checkDestroyedAndRun(() -> mDelegate.classifyText(request)); } @Override public TextLinks generateLinks(TextLinks.Request request) { - checkDestroyed(); - return mDelegate.generateLinks(request); + return checkDestroyedAndRun(() -> mDelegate.generateLinks(request)); } @Override public ConversationActions suggestConversationActions(ConversationActions.Request request) { - checkDestroyed(); - return mDelegate.suggestConversationActions(request); + return checkDestroyedAndRun(() -> mDelegate.suggestConversationActions(request)); } @Override public TextLanguage detectLanguage(TextLanguage.Request request) { - checkDestroyed(); - return mDelegate.detectLanguage(request); + return checkDestroyedAndRun(() -> mDelegate.detectLanguage(request)); } @Override public int getMaxGenerateLinksTextLength() { - checkDestroyed(); - return mDelegate.getMaxGenerateLinksTextLength(); + return checkDestroyedAndRun(mDelegate::getMaxGenerateLinksTextLength); } @Override public void onSelectionEvent(SelectionEvent event) { - try { - if (mEventHelper.sanitizeEvent(event)) { - mDelegate.onSelectionEvent(event); + checkDestroyedAndRun(() -> { + try { + if (mEventHelper.sanitizeEvent(event)) { + mDelegate.onSelectionEvent(event); + } + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier selection event", e); } - } catch (Exception e) { - // Avoid crashing for event reporting. - Log.e(LOG_TAG, "Error reporting text classifier selection event", e); - } + return null; + }); } @Override public void onTextClassifierEvent(TextClassifierEvent event) { - try { - event.mHiddenTempSessionId = mSessionId; - mDelegate.onTextClassifierEvent(event); - } catch (Exception e) { - // Avoid crashing for event reporting. - Log.e(LOG_TAG, "Error reporting text classifier event", e); - } + checkDestroyedAndRun(() -> { + try { + event.mHiddenTempSessionId = mSessionId; + mDelegate.onTextClassifierEvent(event); + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier event", e); + } + return null; + }); } @Override public void destroy() { - mCleaner.clean(); - mDestroyed = true; + synchronized (mLock) { + if (!mDestroyed) { + mCleaner.clean(); + mDestroyed = true; + } + } } @Override public boolean isDestroyed() { - return mDestroyed; + synchronized (mLock) { + return mDestroyed; + } } /** - * @throws IllegalStateException if this TextClassification session has been destroyed. + * Check whether the TextClassification Session was destroyed before and after the actual API + * invocation, and return response if not. + * + * @param responseSupplier a Supplier that represents a TextClassifier call + * @return the response of the TextClassifier call + * @throws IllegalStateException if this TextClassification session was destroyed before the + * call returned * @see #isDestroyed() * @see #destroy() */ - private void checkDestroyed() { - if (mDestroyed) { - throw new IllegalStateException("This TextClassification session has been destroyed"); + private <T> T checkDestroyedAndRun(Supplier<T> responseSupplier) { + if (!isDestroyed()) { + T response = responseSupplier.get(); + synchronized (mLock) { + if (!mDestroyed) { + return response; + } + } } + throw new IllegalStateException( + "This TextClassification session has been destroyed"); } /** diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 7683067958d8..60f8bb7ebe6c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -154,6 +154,10 @@ public class Editor { // Specifies whether to use the magnifier when pressing the insertion or selection handles. private static final boolean FLAG_USE_MAGNIFIER = true; + // Specifies how far to make the cursor start float when drag the cursor away from the + // beginning or end of the line. + private static final int CURSOR_START_FLOAT_DISTANCE_PX = 20; + private static final int DELAY_BEFORE_HANDLE_FADES_OUT = 4000; private static final int RECENT_CUT_COPY_DURATION_MS = 15 * 1000; // 15 seconds in millis @@ -289,6 +293,9 @@ public class Editor { private boolean mRenderCursorRegardlessTiming; private Blink mBlink; + // Whether to let magnifier draw cursor on its surface. This is for floating cursor effect. + // And it can only be true when |mNewMagnifierEnabled| is true. + private boolean mDrawCursorOnMagnifier; boolean mCursorVisible = true; boolean mSelectAllOnFocus; boolean mTextIsSelectable; @@ -890,7 +897,7 @@ public class Editor { } boolean enabled = windowSupportsHandles && mTextView.getLayout() != null; - mInsertionControllerEnabled = enabled && isCursorVisible(); + mInsertionControllerEnabled = enabled && (mDrawCursorOnMagnifier || isCursorVisible()); mSelectionControllerEnabled = enabled && mTextView.textCanBeSelected(); if (!mInsertionControllerEnabled) { @@ -5101,26 +5108,38 @@ public class Editor { final int[] textViewLocationOnScreen = new int[2]; mTextView.getLocationOnScreen(textViewLocationOnScreen); final float touchXInView = event.getRawX() - textViewLocationOnScreen[0]; - float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) ^ rtl)) { - leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); - } else { - leftBound += mTextView.getLayout().getLineLeft(lineNumber); - } - if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) ^ rtl)) { - rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + float leftBound, rightBound; + if (mNewMagnifierEnabled) { + leftBound = 0; + rightBound = mTextView.getWidth(); + if (touchXInView < leftBound || touchXInView > rightBound) { + // The touch is too far from the current line / selection, so hide the magnifier. + return false; + } } else { - rightBound += mTextView.getLayout().getLineRight(lineNumber); - } - leftBound *= mTextViewScaleX; - rightBound *= mTextViewScaleX; - final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth() - / mMagnifierAnimator.mMagnifier.getZoom()); - if (touchXInView < leftBound - contentWidth / 2 - || touchXInView > rightBound + contentWidth / 2) { - // The touch is too far from the current line / selection, so hide the magnifier. - return false; + leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_END) + ^ rtl)) { + leftBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + leftBound += mTextView.getLayout().getLineLeft(lineNumber); + } + if (sameLineSelection && ((trigger == MagnifierHandleTrigger.SELECTION_START) + ^ rtl)) { + rightBound += getHorizontal(mTextView.getLayout(), otherHandleOffset); + } else { + rightBound += mTextView.getLayout().getLineRight(lineNumber); + } + leftBound *= mTextViewScaleX; + rightBound *= mTextViewScaleX; + final float contentWidth = Math.round(mMagnifierAnimator.mMagnifier.getWidth() + / mMagnifierAnimator.mMagnifier.getZoom()); + if (touchXInView < leftBound - contentWidth / 2 + || touchXInView > rightBound + contentWidth / 2) { + // The touch is too far from the current line / selection, so hide the magnifier. + return false; + } } final float scaledTouchXInView; @@ -5178,7 +5197,8 @@ public class Editor { final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y, magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(), magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight()); - setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect)); + setVisible(!handleOverlapsMagnifier(HandleView.this, magnifierRect) + && !mDrawCursorOnMagnifier); final HandleView otherHandle = getOtherSelectionHandle(); if (otherHandle != null) { otherHandle.setVisible(!handleOverlapsMagnifier(otherHandle, magnifierRect)); @@ -5208,7 +5228,20 @@ public class Editor { lineLeft += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); int lineRight = (int) layout.getLineRight(line); lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); - mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight); + mDrawCursorOnMagnifier = + showPosInView.x < lineLeft - CURSOR_START_FLOAT_DISTANCE_PX + || showPosInView.x > lineRight + CURSOR_START_FLOAT_DISTANCE_PX; + mMagnifierAnimator.mMagnifier.setDrawCursor( + mDrawCursorOnMagnifier, mDrawableForCursor); + boolean cursorVisible = mCursorVisible; + // Updates cursor visibility, so that the real cursor and the float cursor on + // magnifier surface won't appear at the same time. + mCursorVisible = !mDrawCursorOnMagnifier; + if (mCursorVisible && !cursorVisible) { + // When the real cursor is a drawable, hiding/showing it would change its + // bounds. So, call updateCursorPosition() to correct its position. + updateCursorPosition(); + } final int lineHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); float zoom = mInitialZoom; @@ -5230,6 +5263,11 @@ public class Editor { if (mMagnifierAnimator != null) { mMagnifierAnimator.dismiss(); mRenderCursorRegardlessTiming = false; + mDrawCursorOnMagnifier = false; + if (!mCursorVisible) { + mCursorVisible = true; + mTextView.invalidate(); + } resumeBlink(); setVisible(true); final HandleView otherHandle = getOtherSelectionHandle(); diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 89206fda39f3..c72eed45e794 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -149,9 +149,6 @@ public final class Magnifier { private int mLeftCutWidth = 0; // The width of the cut region on the right edge of the pixel copy source rect. private int mRightCutWidth = 0; - // The horizontal bounds of the content source in pixels, relative to the view. - private int mLeftBound = Integer.MIN_VALUE; - private int mRightBound = Integer.MAX_VALUE; // The width of the ramp region in pixels on the left & right sides of the fish-eye effect. private final int mRamp; @@ -244,18 +241,6 @@ public final class Magnifier { } /** - * Sets the horizontal bounds of the source when showing the magnifier. - * This is used for new style magnifier. e.g. limit the source bounds by the text line bounds. - * - * @param left the left of the bounds, relative to the view. - * @param right the right of the bounds, relative to the view. - */ - void setSourceHorizontalBounds(int left, int right) { - mLeftBound = left; - mRightBound = right; - } - - /** * Shows the magnifier on the screen. The method takes the coordinates of the center * of the content source going to be magnified and copied to the magnifier. The coordinates * are relative to the top left corner of the magnified view. The magnifier will be @@ -280,6 +265,14 @@ public final class Magnifier { sourceCenterY + mDefaultVerticalSourceToMagnifierOffset); } + private Drawable mCursorDrawable; + private boolean mDrawCursorEnabled; + + void setDrawCursor(boolean enabled, Drawable cursorDrawable) { + mDrawCursorEnabled = enabled; + mCursorDrawable = cursorDrawable; + } + /** * Shows the magnifier on the screen at a position that is independent from its content * position. The first two arguments represent the coordinates of the center of the @@ -309,8 +302,7 @@ public final class Magnifier { magnifierCenterX = mClampedCenterZoomCoords.x - mViewCoordinatesInSurface[0]; magnifierCenterY = mClampedCenterZoomCoords.y - mViewCoordinatesInSurface[1]; - // mLeftBound & mRightBound (typically the text line left/right) is for magnified - // content. However the PixelCopy requires the pre-magnified bounds. + // PixelCopy requires the pre-magnified bounds. // The below logic calculates the leftBound & rightBound for the pre-magnified bounds. final float rampPre = (mSourceWidth - (mSourceWidth - 2 * mRamp) / mZoom) / 2; @@ -318,7 +310,7 @@ public final class Magnifier { // Calculates the pre-zoomed left edge. // The leftEdge moves from the left of view towards to sourceCenterX, considering the // fisheye-like zooming. - final float x0 = sourceCenterX - mSourceWidth / 2; + final float x0 = sourceCenterX - mSourceWidth / 2f; final float rampX0 = x0 + mRamp; float leftEdge = 0; if (leftEdge > rampX0) { @@ -330,12 +322,12 @@ public final class Magnifier { // increase per ramp zoom (ramp / rampPre). leftEdge = x0 + rampPre - (rampX0 - leftEdge) * rampPre / mRamp; } - int leftBound = Math.min(Math.max((int) leftEdge, mLeftBound), mRightBound); + int leftBound = Math.min((int) leftEdge, mView.getWidth()); // Calculates the pre-zoomed right edge. // The rightEdge moves from the right of view towards to sourceCenterX, considering the // fisheye-like zooming. - final float x1 = sourceCenterX + mSourceWidth / 2; + final float x1 = sourceCenterX + mSourceWidth / 2f; final float rampX1 = x1 - mRamp; float rightEdge = mView.getWidth(); if (rightEdge < rampX1) { @@ -347,7 +339,7 @@ public final class Magnifier { // increase per ramp zoom (ramp / rampPre). rightEdge = x1 - rampPre + (rightEdge - rampX1) * rampPre / mRamp; } - int rightBound = Math.max(leftBound, Math.min((int) rightEdge, mRightBound)); + int rightBound = Math.max(leftBound, (int) rightEdge); // Gets the startX for new style, which should be bounded by the horizontal bounds. // Also calculates the left/right cut width for pixel copy. @@ -772,6 +764,23 @@ public final class Magnifier { } } + private void maybeDrawCursor(Canvas canvas) { + if (mDrawCursorEnabled) { + if (mCursorDrawable != null) { + mCursorDrawable.setBounds( + mSourceWidth / 2, 0, + mSourceWidth / 2 + mCursorDrawable.getIntrinsicWidth(), mSourceHeight); + mCursorDrawable.draw(canvas); + } else { + Paint paint = new Paint(); + paint.setColor(Color.BLACK); // The cursor on magnifier is by default in black. + canvas.drawRect( + new Rect(mSourceWidth / 2 - 1, 0, mSourceWidth / 2 + 1, mSourceHeight), + paint); + } + } + } + private void performPixelCopy(final int startXInSurface, final int startYInSurface, final boolean updateWindowPosition) { if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) { @@ -827,8 +836,10 @@ public final class Magnifier { final Rect dstRect = new Rect(mLeftCutWidth, 0, mSourceWidth - mRightCutWidth, bitmap.getHeight()); can.drawBitmap(bitmap, null, dstRect, null); + maybeDrawCursor(can); mWindow.updateContent(newBitmap); } else { + maybeDrawCursor(new Canvas(bitmap)); mWindow.updateContent(bitmap); } } 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..fd90b56426aa 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -206,6 +206,7 @@ public class ChooserActivity extends ResolverActivity implements public static final int SELECTION_TYPE_APP = 2; public static final int SELECTION_TYPE_STANDARD = 3; public static final int SELECTION_TYPE_COPY = 4; + public static final int SELECTION_TYPE_NEARBY = 5; private static final int SCROLL_STATUS_IDLE = 0; private static final int SCROLL_STATUS_SCROLLING_VERTICAL = 1; @@ -784,8 +785,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() @@ -1135,7 +1136,8 @@ public class ChooserActivity extends ResolverActivity implements return displayContentPreview(previewType, targetIntent, getLayoutInflater(), parent); } - private ComponentName getNearbySharingComponent() { + @VisibleForTesting + protected ComponentName getNearbySharingComponent() { String nearbyComponent = Settings.Secure.getString( getContentResolver(), Settings.Secure.NEARBY_SHARING_COMPONENT); @@ -1148,7 +1150,8 @@ public class ChooserActivity extends ResolverActivity implements return ComponentName.unflattenFromString(nearbyComponent); } - private TargetInfo getNearbySharingTarget(Intent originalIntent) { + @VisibleForTesting + protected TargetInfo getNearbySharingTarget(Intent originalIntent) { final ComponentName cn = getNearbySharingComponent(); if (cn == null) return null; @@ -1216,14 +1219,21 @@ public class ChooserActivity extends ResolverActivity implements final TargetInfo ti = getNearbySharingTarget(originalIntent); if (ti == null) return null; - return createActionButton( + final Button b = createActionButton( ti.getDisplayIcon(this), ti.getDisplayLabel(), (View unused) -> { + // Log share completion via nearby + getChooserActivityLogger().logShareTargetSelected( + SELECTION_TYPE_NEARBY, + "", + -1); safelyStartActivity(ti); finish(); } ); + b.setId(R.id.chooser_nearby_button); + return b; } private void addActionButton(ViewGroup parent, Button b) { @@ -2616,7 +2626,9 @@ public class ChooserActivity extends ResolverActivity implements } } - static final class EmptyTargetInfo extends NotSelectableTargetInfo { + protected static final class EmptyTargetInfo extends NotSelectableTargetInfo { + public EmptyTargetInfo() {} + public Drawable getDisplayIcon(Context context) { return null; } diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java index c26bac437915..426859e1d527 100644 --- a/core/java/com/android/internal/app/ChooserActivityLogger.java +++ b/core/java/com/android/internal/app/ChooserActivityLogger.java @@ -116,7 +116,9 @@ public interface ChooserActivityLogger { @UiEvent(doc = "User selected a standard target.") SHARESHEET_STANDARD_TARGET_SELECTED(234), @UiEvent(doc = "User selected the copy target.") - SHARESHEET_COPY_TARGET_SELECTED(235); + SHARESHEET_COPY_TARGET_SELECTED(235), + @UiEvent(doc = "User selected the nearby target.") + SHARESHEET_NEARBY_TARGET_SELECTED(626); private final int mId; SharesheetTargetSelectedEvent(int id) { @@ -136,6 +138,8 @@ public interface ChooserActivityLogger { return SHARESHEET_STANDARD_TARGET_SELECTED; case ChooserActivity.SELECTION_TYPE_COPY: return SHARESHEET_COPY_TARGET_SELECTED; + case ChooserActivity.SELECTION_TYPE_NEARBY: + return SHARESHEET_NEARBY_TARGET_SELECTED; default: return INVALID; } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index 201626abd820..f5bef0b006f5 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -74,6 +74,10 @@ public class BinderCallsStats implements BinderInternal.Observer { // Whether to collect all the data: cpu + exceptions + reply/request sizes. private boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT; + // If set to true, indicates that all transactions for specific UIDs are being + // recorded, ignoring sampling. The UidEntry.recordAllTransactions flag is also set + // for the UIDs being tracked. + private boolean mRecordingAllTransactionsForUid; // Sampling period to control how often to track CPU usage. 1 means all calls, 100 means ~1 out // of 100 requests. private int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; @@ -178,7 +182,8 @@ public class BinderCallsStats implements BinderInternal.Observer { @Override @Nullable public CallSession callStarted(Binder binder, int code, int workSourceUid) { - if (mDeviceState == null || mDeviceState.isCharging()) { + if (!mRecordingAllTransactionsForUid + && (mDeviceState == null || mDeviceState.isCharging())) { return null; } @@ -190,7 +195,9 @@ public class BinderCallsStats implements BinderInternal.Observer { s.exceptionThrown = false; s.cpuTimeStarted = -1; s.timeStarted = -1; - if (shouldRecordDetailedData()) { + s.recordedCall = shouldRecordDetailedData(); + + if (mRecordingAllTransactionsForUid || s.recordedCall) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); } @@ -218,8 +225,17 @@ public class BinderCallsStats implements BinderInternal.Observer { private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize, int workSourceUid) { - // Non-negative time signals we need to record data for this call. - final boolean recordCall = s.cpuTimeStarted >= 0; + UidEntry uidEntry = null; + final boolean recordCall; + if (s.recordedCall) { + recordCall = true; + } else if (mRecordingAllTransactionsForUid) { + uidEntry = getUidEntry(workSourceUid); + recordCall = uidEntry.recordAllTransactions; + } else { + recordCall = false; + } + final long duration; final long latencyDuration; if (recordCall) { @@ -238,14 +254,17 @@ public class BinderCallsStats implements BinderInternal.Observer { synchronized (mLock) { // This was already checked in #callStart but check again while synchronized. - if (mDeviceState == null || mDeviceState.isCharging()) { + if (!mRecordingAllTransactionsForUid + && (mDeviceState == null || mDeviceState.isCharging())) { return; } - final UidEntry uidEntry = getUidEntry(workSourceUid); + if (uidEntry == null) { + uidEntry = getUidEntry(workSourceUid); + } + uidEntry.callCount++; uidEntry.incrementalCallCount++; - if (recordCall) { uidEntry.cpuTimeMicros += duration; uidEntry.recordedCallCount++; @@ -357,28 +376,67 @@ public class BinderCallsStats implements BinderInternal.Observer { for (int entryIdx = 0; entryIdx < uidEntriesSize; entryIdx++) { final UidEntry entry = mUidEntries.valueAt(entryIdx); for (CallStat stat : entry.getCallStatsList()) { - ExportedCallStat exported = new ExportedCallStat(); - exported.workSourceUid = entry.workSourceUid; - exported.callingUid = stat.callingUid; - exported.className = stat.binderClass.getName(); - exported.binderClass = stat.binderClass; - exported.transactionCode = stat.transactionCode; - exported.screenInteractive = stat.screenInteractive; - exported.cpuTimeMicros = stat.cpuTimeMicros; - exported.maxCpuTimeMicros = stat.maxCpuTimeMicros; - exported.latencyMicros = stat.latencyMicros; - exported.maxLatencyMicros = stat.maxLatencyMicros; - exported.recordedCallCount = stat.recordedCallCount; - exported.callCount = stat.callCount; - exported.maxRequestSizeBytes = stat.maxRequestSizeBytes; - exported.maxReplySizeBytes = stat.maxReplySizeBytes; - exported.exceptionCount = stat.exceptionCount; - resultCallStats.add(exported); + resultCallStats.add(getExportedCallStat(entry.workSourceUid, stat)); } } } // Resolve codes outside of the lock since it can be slow. + resolveBinderMethodNames(resultCallStats); + + // Debug entries added to help validate the data. + if (mAddDebugEntries && mBatteryStopwatch != null) { + resultCallStats.add(createDebugEntry("start_time_millis", mStartElapsedTime)); + resultCallStats.add(createDebugEntry("end_time_millis", SystemClock.elapsedRealtime())); + resultCallStats.add( + createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis())); + resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval)); + } + + return resultCallStats; + } + + /** + * This method is expensive to call. + */ + public ArrayList<ExportedCallStat> getExportedCallStats(int workSourceUid) { + ArrayList<ExportedCallStat> resultCallStats = new ArrayList<>(); + synchronized (mLock) { + final UidEntry entry = getUidEntry(workSourceUid); + for (CallStat stat : entry.getCallStatsList()) { + resultCallStats.add(getExportedCallStat(workSourceUid, stat)); + } + } + + // Resolve codes outside of the lock since it can be slow. + resolveBinderMethodNames(resultCallStats); + + return resultCallStats; + } + + private ExportedCallStat getExportedCallStat(int workSourceUid, CallStat stat) { + ExportedCallStat exported = new ExportedCallStat(); + exported.workSourceUid = workSourceUid; + exported.callingUid = stat.callingUid; + exported.className = stat.binderClass.getName(); + exported.binderClass = stat.binderClass; + exported.transactionCode = stat.transactionCode; + exported.screenInteractive = stat.screenInteractive; + exported.cpuTimeMicros = stat.cpuTimeMicros; + exported.maxCpuTimeMicros = stat.maxCpuTimeMicros; + exported.latencyMicros = stat.latencyMicros; + exported.maxLatencyMicros = stat.maxLatencyMicros; + exported.recordedCallCount = stat.recordedCallCount; + exported.callCount = stat.callCount; + exported.maxRequestSizeBytes = stat.maxRequestSizeBytes; + exported.maxReplySizeBytes = stat.maxReplySizeBytes; + exported.exceptionCount = stat.exceptionCount; + return exported; + } + + private void resolveBinderMethodNames( + ArrayList<ExportedCallStat> resultCallStats) { + // Resolve codes outside of the lock since it can be slow. ExportedCallStat previous = null; String previousMethodName = null; resultCallStats.sort(BinderCallsStats::compareByBinderClassAndCode); @@ -398,17 +456,6 @@ public class BinderCallsStats implements BinderInternal.Observer { exported.methodName = methodName; previous = exported; } - - // Debug entries added to help validate the data. - if (mAddDebugEntries && mBatteryStopwatch != null) { - resultCallStats.add(createDebugEntry("start_time_millis", mStartElapsedTime)); - resultCallStats.add(createDebugEntry("end_time_millis", SystemClock.elapsedRealtime())); - resultCallStats.add( - createDebugEntry("battery_time_millis", mBatteryStopwatch.getMillis())); - resultCallStats.add(createDebugEntry("sampling_interval", mPeriodicSamplingInterval)); - } - - return resultCallStats; } private ExportedCallStat createDebugEntry(String variableName, long value) { @@ -432,33 +479,24 @@ public class BinderCallsStats implements BinderInternal.Observer { } /** Writes the collected statistics to the supplied {@link PrintWriter}.*/ - public void dump(PrintWriter pw, AppIdToPackageMap packageMap, boolean verbose) { + public void dump(PrintWriter pw, AppIdToPackageMap packageMap, int workSourceUid, + boolean verbose) { synchronized (mLock) { - dumpLocked(pw, packageMap, verbose); + dumpLocked(pw, packageMap, workSourceUid, verbose); } } - private void dumpLocked(PrintWriter pw, AppIdToPackageMap packageMap, boolean verbose) { - long totalCallsCount = 0; - long totalRecordedCallsCount = 0; - long totalCpuTime = 0; + private void dumpLocked(PrintWriter pw, AppIdToPackageMap packageMap, int workSourceUid, + boolean verbose) { + if (workSourceUid != Process.INVALID_UID) { + verbose = true; + } pw.print("Start time: "); pw.println(DateFormat.format("yyyy-MM-dd HH:mm:ss", mStartCurrentTime)); pw.print("On battery time (ms): "); pw.println(mBatteryStopwatch != null ? mBatteryStopwatch.getMillis() : 0); pw.println("Sampling interval period: " + mPeriodicSamplingInterval); - final List<UidEntry> entries = new ArrayList<>(); - final int uidEntriesSize = mUidEntries.size(); - for (int i = 0; i < uidEntriesSize; i++) { - UidEntry e = mUidEntries.valueAt(i); - entries.add(e); - totalCpuTime += e.cpuTimeMicros; - totalRecordedCallsCount += e.recordedCallCount; - totalCallsCount += e.callCount; - } - - entries.sort(Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); final String datasetSizeDesc = verbose ? "" : "(top 90% by cpu time) "; final StringBuilder sb = new StringBuilder(); pw.println("Per-UID raw data " + datasetSizeDesc @@ -467,10 +505,15 @@ public class BinderCallsStats implements BinderInternal.Observer { + "latency_time_micros, max_latency_time_micros, exception_count, " + "max_request_size_bytes, max_reply_size_bytes, recorded_call_count, " + "call_count):"); - final List<ExportedCallStat> exportedCallStats = getExportedCallStats(); + final List<ExportedCallStat> exportedCallStats; + if (workSourceUid != Process.INVALID_UID) { + exportedCallStats = getExportedCallStats(workSourceUid); + } else { + exportedCallStats = getExportedCallStats(); + } exportedCallStats.sort(BinderCallsStats::compareByCpuDesc); for (ExportedCallStat e : exportedCallStats) { - if (e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) { + if (e.methodName != null && e.methodName.startsWith(DEBUG_ENTRY_PREFIX)) { // Do not dump debug entries. continue; } @@ -494,6 +537,30 @@ public class BinderCallsStats implements BinderInternal.Observer { pw.println(sb); } pw.println(); + final List<UidEntry> entries = new ArrayList<>(); + long totalCallsCount = 0; + long totalRecordedCallsCount = 0; + long totalCpuTime = 0; + + if (workSourceUid != Process.INVALID_UID) { + UidEntry e = getUidEntry(workSourceUid); + entries.add(e); + totalCpuTime += e.cpuTimeMicros; + totalRecordedCallsCount += e.recordedCallCount; + totalCallsCount += e.callCount; + } else { + final int uidEntriesSize = mUidEntries.size(); + for (int i = 0; i < uidEntriesSize; i++) { + UidEntry e = mUidEntries.valueAt(i); + entries.add(e); + totalCpuTime += e.cpuTimeMicros; + totalRecordedCallsCount += e.recordedCallCount; + totalCallsCount += e.callCount; + } + entries.sort( + Comparator.<UidEntry>comparingDouble(value -> value.cpuTimeMicros).reversed()); + } + pw.println("Per-UID Summary " + datasetSizeDesc + "(cpu_time, % of total cpu_time, recorded_call_count, call_count, package/uid):"); final List<UidEntry> summaryEntries = verbose ? entries @@ -505,10 +572,13 @@ public class BinderCallsStats implements BinderInternal.Observer { entry.recordedCallCount, entry.callCount, uidStr)); } pw.println(); - pw.println(String.format(" Summary: total_cpu_time=%d, " - + "calls_count=%d, avg_call_cpu_time=%.0f", - totalCpuTime, totalCallsCount, (double) totalCpuTime / totalRecordedCallsCount)); - pw.println(); + if (workSourceUid == Process.INVALID_UID) { + pw.println(String.format(" Summary: total_cpu_time=%d, " + + "calls_count=%d, avg_call_cpu_time=%.0f", + totalCpuTime, totalCallsCount, + (double) totalCpuTime / totalRecordedCallsCount)); + pw.println(); + } pw.println("Exceptions thrown (exception_count, class_name):"); final List<Pair<String, Integer>> exceptionEntries = new ArrayList<>(); @@ -590,6 +660,22 @@ public class BinderCallsStats implements BinderInternal.Observer { } } + /** + * Marks the specified work source UID for total binder call tracking: detailed information + * will be recorded for all calls from this source ID. + * + * This is expensive and can cause memory pressure, therefore this mode should only be used + * for debugging. + */ + public void recordAllCallsForWorkSourceUid(int workSourceUid) { + setDetailedTracking(true); + + Slog.i(TAG, "Recording all Binder calls for UID: " + workSourceUid); + UidEntry uidEntry = getUidEntry(workSourceUid); + uidEntry.recordAllTransactions = true; + mRecordingAllTransactionsForUid = true; + } + public void setAddDebugEntries(boolean addDebugEntries) { mAddDebugEntries = addDebugEntries; } @@ -637,6 +723,7 @@ public class BinderCallsStats implements BinderInternal.Observer { if (mBatteryStopwatch != null) { mBatteryStopwatch.reset(); } + mRecordingAllTransactionsForUid = false; } } @@ -767,6 +854,8 @@ public class BinderCallsStats implements BinderInternal.Observer { public long cpuTimeMicros; // Call count that gets reset after delivery to BatteryStats public long incrementalCallCount; + // Indicates that all transactions for the UID must be tracked + public boolean recordAllTransactions; UidEntry(int uid) { this.workSourceUid = uid; diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java index f14d5f2bbbeb..2645b8e84cf1 100644 --- a/core/java/com/android/internal/os/BinderInternal.java +++ b/core/java/com/android/internal/os/BinderInternal.java @@ -85,9 +85,10 @@ public class BinderInternal { long timeStarted; // Should be set to one when an exception is thrown. boolean exceptionThrown; + // Detailed information should be recorded for this call when it ends. + public boolean recordedCall; } - /** * Responsible for resolving a work source. */ diff --git a/services/core/java/com/android/server/wm/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java index 51725cecbc74..73d148c1f233 100644 --- a/services/core/java/com/android/server/wm/ProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,11 +14,9 @@ * limitations under the License. */ -package com.android.server.wm; +package com.android.internal.protolog; -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.IProtoLogGroup; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.IProtoLogGroup; /** * Defines logging groups for ProtoLog. @@ -118,16 +116,6 @@ public enum ProtoLogGroup implements IProtoLogGroup { this.mLogToLogcat = logToLogcat; } - /** - * Test function for automated integration tests. Can be also called manually from adb shell. - */ - @VisibleForTesting - public static void testProtoLog() { - ProtoLog.e(ProtoLogGroup.TEST_GROUP, - "Test completed successfully: %b %d %o %x %e %g %f %% %s.", - true, 1, 2, 3, 0.4, 0.5, 0.6, "ok"); - } - private static class Consts { private static final String TAG_WM = "WindowManager"; diff --git a/services/core/java/com/android/server/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index c9d42c854b54..6874f10e6abc 100644 --- a/services/core/java/com/android/server/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,20 +14,20 @@ * limitations under the License. */ -package com.android.server.protolog; - -import static com.android.server.protolog.ProtoLogFileProto.LOG; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; -import static com.android.server.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; -import static com.android.server.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; -import static com.android.server.protolog.ProtoLogFileProto.VERSION; -import static com.android.server.protolog.ProtoLogMessage.BOOLEAN_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.DOUBLE_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; -import static com.android.server.protolog.ProtoLogMessage.MESSAGE_HASH; -import static com.android.server.protolog.ProtoLogMessage.SINT64_PARAMS; -import static com.android.server.protolog.ProtoLogMessage.STR_PARAMS; +package com.android.internal.protolog; + +import static com.android.internal.protolog.ProtoLogFileProto.LOG; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_H; +import static com.android.internal.protolog.ProtoLogFileProto.MAGIC_NUMBER_L; +import static com.android.internal.protolog.ProtoLogFileProto.REAL_TIME_TO_ELAPSED_TIME_OFFSET_MILLIS; +import static com.android.internal.protolog.ProtoLogFileProto.VERSION; +import static com.android.internal.protolog.ProtoLogMessage.BOOLEAN_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.DOUBLE_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.ELAPSED_REALTIME_NANOS; +import static com.android.internal.protolog.ProtoLogMessage.MESSAGE_HASH; +import static com.android.internal.protolog.ProtoLogMessage.SINT64_PARAMS; +import static com.android.internal.protolog.ProtoLogMessage.STR_PARAMS; import android.annotation.Nullable; import android.os.ShellCommand; @@ -36,10 +36,9 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.IProtoLogGroup; -import com.android.server.protolog.common.LogDataType; +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogDataType; import com.android.internal.util.TraceBuffer; -import com.android.server.wm.ProtoLogGroup; import java.io.File; import java.io.IOException; @@ -62,7 +61,7 @@ public class ProtoLogImpl { * Must be invoked after every action that could change the result of {@link #isEnabled}, eg. * starting / stopping proto log, or enabling / disabling log groups. */ - static Runnable sCacheUpdater = () -> { }; + public static Runnable sCacheUpdater = () -> { }; private static void addLogGroupEnum(IProtoLogGroup[] config) { for (IProtoLogGroup group : config) { @@ -289,9 +288,7 @@ public class ProtoLogImpl { } } - - @VisibleForTesting - ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { + public ProtoLogImpl(File file, int bufferCapacity, ProtoLogViewerConfigReader viewerConfig) { mLogFile = file; mBuffer = new TraceBuffer(bufferCapacity); mViewerConfig = viewerConfig; diff --git a/services/core/java/com/android/server/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index 494421717800..e381d30da524 100644 --- a/services/core/java/com/android/server/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,9 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog; - -import static com.android.server.protolog.ProtoLogImpl.logAndPrintln; +package com.android.internal.protolog; import org.json.JSONException; import org.json.JSONObject; @@ -80,16 +78,17 @@ public class ProtoLogViewerConfigReader { // Not a messageHash - skip it } } - logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + " log definitions from " - + viewerConfigFilename); + ProtoLogImpl.logAndPrintln(pw, "Loaded " + mLogMessageMap.size() + + " log definitions from " + viewerConfigFilename); } catch (FileNotFoundException e) { - logAndPrintln(pw, "Unable to load log definitions: File " + ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: File " + viewerConfigFilename + " not found." + e); } catch (IOException e) { - logAndPrintln(pw, "Unable to load log definitions: IOException while reading " + ProtoLogImpl.logAndPrintln(pw, + "Unable to load log definitions: IOException while reading " + viewerConfigFilename + ". " + e); } catch (JSONException e) { - logAndPrintln(pw, + ProtoLogImpl.logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading " + viewerConfigFilename + ". " + e); } diff --git a/services/core/java/com/android/server/protolog/common/BitmaskConversionException.java b/core/java/com/android/internal/protolog/common/BitmaskConversionException.java index 7bb27b2d9bcd..68b9d6910b57 100644 --- a/services/core/java/com/android/server/protolog/common/BitmaskConversionException.java +++ b/core/java/com/android/internal/protolog/common/BitmaskConversionException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; /** * Error while converting a bitmask representing a list of LogDataTypes. diff --git a/services/core/java/com/android/server/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java index 2c65341453e9..e3db46832a6f 100644 --- a/services/core/java/com/android/server/protolog/common/IProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; /** * Defines a log group configuration object for ProtoLog. Should be implemented as en enum. diff --git a/services/core/java/com/android/server/protolog/common/InvalidFormatStringException.java b/core/java/com/android/internal/protolog/common/InvalidFormatStringException.java index 947bf98eea3c..97d3dfb7e6c2 100644 --- a/services/core/java/com/android/server/protolog/common/InvalidFormatStringException.java +++ b/core/java/com/android/internal/protolog/common/InvalidFormatStringException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; /** * Unsupported/invalid message format string error. diff --git a/services/core/java/com/android/server/protolog/common/LogDataType.java b/core/java/com/android/internal/protolog/common/LogDataType.java index e73b41abddc7..651932a7ba7e 100644 --- a/services/core/java/com/android/server/protolog/common/LogDataType.java +++ b/core/java/com/android/internal/protolog/common/LogDataType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; import java.util.ArrayList; import java.util.List; diff --git a/services/core/java/com/android/server/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java index b631bcb23f5f..ab58d351d3b9 100644 --- a/services/core/java/com/android/server/protolog/common/ProtoLog.java +++ b/core/java/com/android/internal/protolog/common/ProtoLog.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; /** * ProtoLog API - exposes static logging methods. Usage of this API is similar diff --git a/core/java/com/android/internal/util/StatLogger.java b/core/java/com/android/internal/util/StatLogger.java index 29568d5020e3..2d65090ce51e 100644 --- a/core/java/com/android/internal/util/StatLogger.java +++ b/core/java/com/android/internal/util/StatLogger.java @@ -84,7 +84,7 @@ public class StatLogger { * give it back to the {@link #logDurationStat(int, long)}} after the event. */ public long getTime() { - return SystemClock.elapsedRealtimeNanos() / 1000; + return SystemClock.uptimeNanos() / 1000; } /** diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index e35fda1ee76d..d5d635de81d8 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -47,8 +47,9 @@ interface ILockSettings { void resetKeyStore(int userId); VerifyCredentialResponse checkCredential(in LockscreenCredential credential, int userId, in ICheckCredentialProgressCallback progressCallback); - VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, long challenge, int userId); - VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, long challenge, int userId); + VerifyCredentialResponse verifyCredential(in LockscreenCredential credential, int userId, int flags); + VerifyCredentialResponse verifyTiedProfileChallenge(in LockscreenCredential credential, int userId, int flags); + VerifyCredentialResponse verifyGatekeeperPassword(in byte[] gatekeeperPassword, long challenge, int userId); boolean checkVoldPassword(int userId); int getCredentialType(int userId); byte[] getHashFactor(in LockscreenCredential currentCredential, int userId); diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index 85a45fd8e0c0..5adbc583140f 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -1,5 +1,6 @@ package com.android.internal.widget; +import android.annotation.NonNull; import android.os.AsyncTask; import com.android.internal.widget.LockPatternUtils.RequestThrottledException; @@ -41,11 +42,11 @@ public final class LockPatternChecker { /** * Invoked when a security verification is finished. * - * @param attestation The attestation that the challenge was verified, or null. + * @param response The response, optionally containing Gatekeeper HAT or Gatekeeper Password * @param throttleTimeoutMs The amount of time in ms to wait before reattempting - * the call. Only non-0 if attestation is null. + * the call. Only non-0 if the response is {@link VerifyCredentialResponse#RESPONSE_RETRY}. */ - void onVerified(byte[] attestation, int throttleTimeoutMs); + void onVerified(@NonNull VerifyCredentialResponse response, int throttleTimeoutMs); } /** @@ -53,33 +54,27 @@ public final class LockPatternChecker { * * @param utils The LockPatternUtils instance to use. * @param credential The credential to check. - * @param challenge The challenge to verify against the credential. * @param userId The user to check against the credential. + * @param flags See {@link LockPatternUtils.VerifyFlag} * @param callback The callback to be invoked with the verification result. */ public static AsyncTask<?, ?, ?> verifyCredential(final LockPatternUtils utils, final LockscreenCredential credential, - final long challenge, final int userId, + final @LockPatternUtils.VerifyFlag int flags, final OnVerifyCallback callback) { // Create a copy of the credential since checking credential is asynchrounous. final LockscreenCredential credentialCopy = credential.duplicate(); - AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() { - private int mThrottleTimeout; - + AsyncTask<Void, Void, VerifyCredentialResponse> task = + new AsyncTask<Void, Void, VerifyCredentialResponse>() { @Override - protected byte[] doInBackground(Void... args) { - try { - return utils.verifyCredential(credentialCopy, challenge, userId); - } catch (RequestThrottledException ex) { - mThrottleTimeout = ex.getTimeoutMs(); - return null; - } + protected VerifyCredentialResponse doInBackground(Void... args) { + return utils.verifyCredential(credentialCopy, userId, flags); } @Override - protected void onPostExecute(byte[] result) { - callback.onVerified(result, mThrottleTimeout); + protected void onPostExecute(@NonNull VerifyCredentialResponse result) { + callback.onVerified(result, result.getTimeout()); credentialCopy.zeroize(); } @@ -141,33 +136,27 @@ public final class LockPatternChecker { * * @param utils The LockPatternUtils instance to use. * @param credential The credential to check. - * @param challenge The challenge to verify against the credential. * @param userId The user to check against the credential. + * @param flags See {@link LockPatternUtils.VerifyFlag} * @param callback The callback to be invoked with the verification result. */ public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils, final LockscreenCredential credential, - final long challenge, final int userId, + final @LockPatternUtils.VerifyFlag int flags, final OnVerifyCallback callback) { - // Create a copy of the credential since checking credential is asynchrounous. + // Create a copy of the credential since checking credential is asynchronous. final LockscreenCredential credentialCopy = credential.duplicate(); - AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() { - private int mThrottleTimeout; - + AsyncTask<Void, Void, VerifyCredentialResponse> task = + new AsyncTask<Void, Void, VerifyCredentialResponse>() { @Override - protected byte[] doInBackground(Void... args) { - try { - return utils.verifyTiedProfileChallenge(credentialCopy, challenge, userId); - } catch (RequestThrottledException ex) { - mThrottleTimeout = ex.getTimeoutMs(); - return null; - } + protected VerifyCredentialResponse doInBackground(Void... args) { + return utils.verifyTiedProfileChallenge(credentialCopy, userId, flags); } @Override - protected void onPostExecute(byte[] result) { - callback.onVerified(result, mThrottleTimeout); + protected void onPostExecute(@NonNull VerifyCredentialResponse response) { + callback.onVerified(response, response.getTimeout()); credentialCopy.zeroize(); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 93690cdfc811..f7370d6a22f9 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -130,6 +130,18 @@ public class LockPatternUtils { public @interface CredentialType {} /** + * Flag provided to {@link #verifyCredential(LockscreenCredential, long, int, int)} . If set, + * the method will return the Gatekeeper Password in the {@link VerifyCredentialResponse}. + */ + public static final int VERIFY_FLAG_RETURN_GK_PW = 1 << 0; + + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, value = { + VERIFY_FLAG_RETURN_GK_PW + }) + public @interface VerifyFlag {} + + /** * Special user id for triggering the FRP verification flow. */ public static final int USER_FRP = UserHandle.USER_NULL + 1; @@ -374,29 +386,46 @@ public class LockPatternUtils { * If credential matches, return an opaque attestation that the challenge was verified. * * @param credential The credential to check. - * @param challenge The challenge to verify against the credential * @param userId The user whose credential is being verified - * @return the attestation that the challenge was verified, or null - * @throws RequestThrottledException if credential verification is being throttled due to - * to many incorrect attempts. + * @param flags See {@link VerifyFlag} * @throws IllegalStateException if called on the main thread. */ - public byte[] verifyCredential(@NonNull LockscreenCredential credential, long challenge, - int userId) throws RequestThrottledException { + @NonNull + public VerifyCredentialResponse verifyCredential(@NonNull LockscreenCredential credential, + int userId, @VerifyFlag int flags) { throwIfCalledOnMainThread(); try { - VerifyCredentialResponse response = getLockSettings().verifyCredential( - credential, challenge, userId); - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - return response.getPayload(); - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { - throw new RequestThrottledException(response.getTimeout()); + final VerifyCredentialResponse response = getLockSettings().verifyCredential( + credential, userId, flags); + if (response == null) { + return VerifyCredentialResponse.ERROR; } else { - return null; + return response; } } catch (RemoteException re) { Log.e(TAG, "failed to verify credential", re); - return null; + return VerifyCredentialResponse.ERROR; + } + } + + /** + * With the Gatekeeper Password returned via {@link #verifyCredential(LockscreenCredential, + * int, int)}, request Gatekeeper to create a HardwareAuthToken wrapping the given + * challenge. + */ + @NonNull + public VerifyCredentialResponse verifyGatekeeperPassword(@NonNull byte[] gatekeeperPassword, + long challenge, int userId) { + try { + final VerifyCredentialResponse response = getLockSettings().verifyGatekeeperPassword( + gatekeeperPassword, challenge, userId); + if (response == null) { + return VerifyCredentialResponse.ERROR; + } + return response; + } catch (RemoteException e) { + Log.e(TAG, "failed to verify gatekeeper password", e); + return VerifyCredentialResponse.ERROR; } } @@ -418,8 +447,9 @@ public class LockPatternUtils { try { VerifyCredentialResponse response = getLockSettings().checkCredential( credential, userId, wrapCallback(progressCallback)); - - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { + if (response == null) { + return false; + } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { return true; } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { throw new RequestThrottledException(response.getTimeout()); @@ -439,30 +469,26 @@ public class LockPatternUtils { * verified. * * @param credential The parent user's credential to check. - * @param challenge The challenge to verify against the credential * @return the attestation that the challenge was verified, or null * @param userId The managed profile user id - * @throws RequestThrottledException if credential verification is being throttled due to - * to many incorrect attempts. + * @param flags See {@link VerifyFlag} * @throws IllegalStateException if called on the main thread. */ - public byte[] verifyTiedProfileChallenge(@NonNull LockscreenCredential credential, - long challenge, int userId) throws RequestThrottledException { + @NonNull + public VerifyCredentialResponse verifyTiedProfileChallenge( + @NonNull LockscreenCredential credential, int userId, @VerifyFlag int flags) { throwIfCalledOnMainThread(); try { - VerifyCredentialResponse response = - getLockSettings().verifyTiedProfileChallenge(credential, challenge, userId); - - if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { - return response.getPayload(); - } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) { - throw new RequestThrottledException(response.getTimeout()); + final VerifyCredentialResponse response = getLockSettings() + .verifyTiedProfileChallenge(credential, userId, flags); + if (response == null) { + return VerifyCredentialResponse.ERROR; } else { - return null; + return response; } } catch (RemoteException re) { Log.e(TAG, "failed to verify tied profile credential", re); - return null; + return VerifyCredentialResponse.ERROR; } } diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java index 55f30fb89253..a488449db019 100644 --- a/core/java/com/android/internal/widget/LockscreenCredential.java +++ b/core/java/com/android/internal/widget/LockscreenCredential.java @@ -48,7 +48,7 @@ import java.util.Objects; * // Process the credential in some way * } * </pre> - * With this construct, we can garantee that there will be no copies of the password left in + * With this construct, we can guarantee that there will be no copies of the password left in * memory when the credential goes out of scope. This should help mitigate certain class of * attacks where the attcker gains read-only access to full device memory (cold boot attack, * unsecured software/hardware memory dumping interfaces such as JTAG). diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java index 7d1c70647092..e09eb4228219 100644 --- a/core/java/com/android/internal/widget/VerifyCredentialResponse.java +++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java @@ -16,11 +16,16 @@ package com.android.internal.widget; +import android.annotation.IntDef; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.service.gatekeeper.GateKeeperResponse; import android.util.Slog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Response object for a ILockSettings credential verification request. * @hide @@ -30,78 +35,114 @@ public final class VerifyCredentialResponse implements Parcelable { public static final int RESPONSE_ERROR = -1; public static final int RESPONSE_OK = 0; public static final int RESPONSE_RETRY = 1; - - public static final VerifyCredentialResponse OK = new VerifyCredentialResponse(); - public static final VerifyCredentialResponse ERROR - = new VerifyCredentialResponse(RESPONSE_ERROR, 0, null); + @IntDef({RESPONSE_ERROR, + RESPONSE_OK, + RESPONSE_RETRY}) + @Retention(RetentionPolicy.SOURCE) + @interface ResponseCode {} + + public static final VerifyCredentialResponse OK = new VerifyCredentialResponse.Builder() + .build(); + public static final VerifyCredentialResponse ERROR = fromError(); private static final String TAG = "VerifyCredentialResponse"; - private int mResponseCode; - private byte[] mPayload; - private int mTimeout; + private final @ResponseCode int mResponseCode; + private final int mTimeout; + @Nullable private final byte[] mGatekeeperHAT; + @Nullable private final byte[] mGatekeeperPw; public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR = new Parcelable.Creator<VerifyCredentialResponse>() { @Override public VerifyCredentialResponse createFromParcel(Parcel source) { - int responseCode = source.readInt(); - VerifyCredentialResponse response = new VerifyCredentialResponse(responseCode, 0, null); - if (responseCode == RESPONSE_RETRY) { - response.setTimeout(source.readInt()); - } else if (responseCode == RESPONSE_OK) { - int size = source.readInt(); - if (size > 0) { - byte[] payload = new byte[size]; - source.readByteArray(payload); - response.setPayload(payload); - } - } - return response; + final @ResponseCode int responseCode = source.readInt(); + final int timeout = source.readInt(); + final byte[] gatekeeperHAT = source.createByteArray(); + final byte[] gatekeeperPassword = source.createByteArray(); + + return new VerifyCredentialResponse(responseCode, timeout, gatekeeperHAT, + gatekeeperPassword); } @Override public VerifyCredentialResponse[] newArray(int size) { return new VerifyCredentialResponse[size]; } - }; - public VerifyCredentialResponse() { - mResponseCode = RESPONSE_OK; - mPayload = null; - } + public static class Builder { + @Nullable private byte[] mGatekeeperHAT; + @Nullable private byte[] mGatekeeperPassword; + /** + * @param gatekeeperHAT Gatekeeper HardwareAuthToken, minted upon successful authentication. + */ + public Builder setGatekeeperHAT(byte[] gatekeeperHAT) { + mGatekeeperHAT = gatekeeperHAT; + return this; + } - public VerifyCredentialResponse(byte[] payload) { - mPayload = payload; - mResponseCode = RESPONSE_OK; + public Builder setGatekeeperPassword(byte[] gatekeeperPassword) { + mGatekeeperPassword = gatekeeperPassword; + return this; + } + + /** + * Builds a VerifyCredentialResponse with {@link #RESPONSE_OK} and any other parameters + * that were preveiously set. + * @return + */ + public VerifyCredentialResponse build() { + return new VerifyCredentialResponse(RESPONSE_OK, + 0 /* timeout */, + mGatekeeperHAT, + mGatekeeperPassword); + } } - public VerifyCredentialResponse(int timeout) { - mTimeout = timeout; - mResponseCode = RESPONSE_RETRY; - mPayload = null; + /** + * Since timeouts are always an error, provide a way to create the VerifyCredentialResponse + * object directly. None of the other fields (Gatekeeper HAT, Gatekeeper Password, etc) + * are valid in this case. Similarly, the response code will always be + * {@link #RESPONSE_RETRY}. + */ + public static VerifyCredentialResponse fromTimeout(int timeout) { + return new VerifyCredentialResponse(RESPONSE_RETRY, + timeout, + null /* gatekeeperHAT */, + null /* gatekeeperPassword */); + } + + /** + * Since error (incorrect password) should never result in any of the other fields from + * being populated, provide a default method to return a VerifyCredentialResponse. + */ + public static VerifyCredentialResponse fromError() { + return new VerifyCredentialResponse(RESPONSE_ERROR, + 0 /* timeout */, + null /* gatekeeperHAT */, + null /* gatekeeperPassword */); } - private VerifyCredentialResponse(int responseCode, int timeout, byte[] payload) { + private VerifyCredentialResponse(@ResponseCode int responseCode, int timeout, + @Nullable byte[] gatekeeperHAT, @Nullable byte[] gatekeeperPassword) { mResponseCode = responseCode; mTimeout = timeout; - mPayload = payload; + mGatekeeperHAT = gatekeeperHAT; + mGatekeeperPw = gatekeeperPassword; + } + + public VerifyCredentialResponse stripPayload() { + return new VerifyCredentialResponse(mResponseCode, mTimeout, + null /* gatekeeperHAT */, null /* gatekeeperPassword */); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mResponseCode); - if (mResponseCode == RESPONSE_RETRY) { - dest.writeInt(mTimeout); - } else if (mResponseCode == RESPONSE_OK) { - if (mPayload != null) { - dest.writeInt(mPayload.length); - dest.writeByteArray(mPayload); - } else { - dest.writeInt(0); - } - } + dest.writeInt(mTimeout); + dest.writeByteArray(mGatekeeperHAT); + dest.writeByteArray(mGatekeeperPw); } @Override @@ -109,48 +150,51 @@ public final class VerifyCredentialResponse implements Parcelable { return 0; } - public byte[] getPayload() { - return mPayload; + @Nullable + public byte[] getGatekeeperHAT() { + return mGatekeeperHAT; + } + + @Nullable + public byte[] getGatekeeperPw() { + return mGatekeeperPw; } public int getTimeout() { return mTimeout; } - public int getResponseCode() { + public @ResponseCode int getResponseCode() { return mResponseCode; } - private void setTimeout(int timeout) { - mTimeout = timeout; - } - - private void setPayload(byte[] payload) { - mPayload = payload; + public boolean isMatched() { + return mResponseCode == RESPONSE_OK; } - public VerifyCredentialResponse stripPayload() { - return new VerifyCredentialResponse(mResponseCode, mTimeout, new byte[0]); + @Override + public String toString() { + return "Response: " + mResponseCode + + ", GK HAT: " + (mGatekeeperHAT != null) + + ", GK PW: " + (mGatekeeperPw != null); } public static VerifyCredentialResponse fromGateKeeperResponse( GateKeeperResponse gateKeeperResponse) { - VerifyCredentialResponse response; int responseCode = gateKeeperResponse.getResponseCode(); if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { - response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout()); + return fromTimeout(gateKeeperResponse.getTimeout()); } else if (responseCode == GateKeeperResponse.RESPONSE_OK) { byte[] token = gateKeeperResponse.getPayload(); if (token == null) { // something's wrong if there's no payload with a challenge Slog.e(TAG, "verifyChallenge response had no associated payload"); - response = VerifyCredentialResponse.ERROR; + return fromError(); } else { - response = new VerifyCredentialResponse(token); + return new VerifyCredentialResponse.Builder().setGatekeeperHAT(token).build(); } } else { - response = VerifyCredentialResponse.ERROR; + return fromError(); } - return response; } } diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp index b1f600053b9b..2fba445428f4 100644 --- a/core/jni/android_os_SystemClock.cpp +++ b/core/jni/android_os_SystemClock.cpp @@ -37,10 +37,12 @@ namespace android { static_assert(std::is_same<int64_t, jlong>::value, "jlong isn't an int64_t"); static_assert(std::is_same<decltype(uptimeMillis()), int64_t>::value, "uptimeMillis signature change, expected int64_t return value"); +static_assert(std::is_same<decltype(uptimeNanos()), int64_t>::value, + "uptimeNanos signature change, expected int64_t return value"); static_assert(std::is_same<decltype(elapsedRealtime()), int64_t>::value, - "uptimeMillis signature change, expected int64_t return value"); + "elapsedRealtime signature change, expected int64_t return value"); static_assert(std::is_same<decltype(elapsedRealtimeNano()), int64_t>::value, - "uptimeMillis signature change, expected int64_t return value"); + "elapsedRealtimeNano signature change, expected int64_t return value"); /* * native public static long currentThreadTimeMillis(); @@ -76,6 +78,7 @@ static const JNINativeMethod gMethods[] = { // All of these are @CriticalNative, so we can defer directly to SystemClock.h for // some of these { "uptimeMillis", "()J", (void*) uptimeMillis }, + { "uptimeNanos", "()J", (void*) uptimeNanos }, { "elapsedRealtime", "()J", (void*) elapsedRealtime }, { "elapsedRealtimeNanos", "()J", (void*) elapsedRealtimeNano }, diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index e715be21f146..50a557bb53a1 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -63,6 +63,7 @@ private: void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId, nsecs_t vsyncPeriod) override; + void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} }; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index d6a773fb91e0..85b4fe197980 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -116,7 +116,6 @@ static struct { jfieldID width; jfieldID height; jfieldID useIdentityTransform; - jfieldID rotation; } gDisplayCaptureArgsClassInfo; static struct { @@ -325,8 +324,6 @@ static DisplayCaptureArgs displayCaptureArgsFromObject(JNIEnv* env, captureArgs.useIdentityTransform = env->GetBooleanField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.useIdentityTransform); - captureArgs.rotation = ui::toRotation( - env->GetIntField(displayCaptureArgsObject, gDisplayCaptureArgsClassInfo.rotation)); return captureArgs; } @@ -1849,8 +1846,6 @@ int register_android_view_SurfaceControl(JNIEnv* env) GetFieldIDOrDie(env, displayCaptureArgsClazz, "mHeight", "I"); gDisplayCaptureArgsClassInfo.useIdentityTransform = GetFieldIDOrDie(env, displayCaptureArgsClazz, "mUseIdentityTransform", "Z"); - gDisplayCaptureArgsClassInfo.rotation = - GetFieldIDOrDie(env, displayCaptureArgsClazz, "mRotation", "I"); jclass layerCaptureArgsClazz = FindClassOrDie(env, "android/view/SurfaceControl$LayerCaptureArgs"); diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h index eeda275b811c..d629e0dae6dd 100644 --- a/core/jni/core_jni_helpers.h +++ b/core/jni/core_jni_helpers.h @@ -104,6 +104,31 @@ static inline std::string getStringField(JNIEnv* env, jobject obj, jfieldID fiel return std::string(defaultValue); } +static inline JNIEnv* GetJNIEnvironment(JavaVM* vm, jint version = JNI_VERSION_1_4) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), version) != JNI_OK) { + return nullptr; + } + return env; +} + +static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm, jint version = JNI_VERSION_1_4) { + JNIEnv* env = GetJNIEnvironment(jvm, version); + if (!env) { + int result = jvm->AttachCurrentThread(&env, nullptr); + LOG_ALWAYS_FATAL_IF(result != JNI_OK, "JVM thread attach failed."); + struct VmDetacher { + VmDetacher(JavaVM* vm) : mVm(vm) {} + ~VmDetacher() { mVm->DetachCurrentThread(); } + + private: + JavaVM* const mVm; + }; + static thread_local VmDetacher detacher(jvm); + } + return env; +} + } // namespace android #endif // CORE_JNI_HELPERS 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/proto/android/server/protolog.proto b/core/proto/android/internal/protolog.proto index 34dc55b959c2..fee7a878f860 100644 --- a/core/proto/android/server/protolog.proto +++ b/core/proto/android/internal/protolog.proto @@ -16,7 +16,7 @@ syntax = "proto2"; -package com.android.server.protolog; +package com.android.internal.protolog; option java_multiple_files = true; diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 2e4169e15c3b..4f55bf51c826 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -470,10 +470,10 @@ <string name="permdesc_wakeLock" product="tablet" msgid="2441742939101526277">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string> <string name="permdesc_wakeLock" product="tv" msgid="2329298966735118796">"Permet que l\'aplicació impedeixi que el dispositiu Android TV entri en repòs."</string> <string name="permdesc_wakeLock" product="default" msgid="3689523792074007163">"Permet que l\'aplicació impedeixi que el telèfon entri en repòs."</string> - <string name="permlab_transmitIr" msgid="8077196086358004010">"transmissió d\'infraroigs"</string> - <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs de la tauleta."</string> - <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet que l\'aplicació faci servir el transmissor d\'infraroigs del dispositiu Android TV."</string> - <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet que l\'aplicació utilitzi el transmissor d\'infraroigs del telèfon."</string> + <string name="permlab_transmitIr" msgid="8077196086358004010">"transmissió d\'infrarojos"</string> + <string name="permdesc_transmitIr" product="tablet" msgid="5884738958581810253">"Permet que l\'aplicació utilitzi el transmissor d\'infrarojos de la tauleta."</string> + <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"Permet que l\'aplicació faci servir el transmissor d\'infrarojos del dispositiu Android TV."</string> + <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"Permet que l\'aplicació utilitzi el transmissor d\'infrarojos del telèfon."</string> <string name="permlab_setWallpaper" msgid="6959514622698794511">"establir fons de pantalla"</string> <string name="permdesc_setWallpaper" msgid="2973996714129021397">"Permet que l\'aplicació estableixi el fons de pantalla del sistema."</string> <string name="permlab_setWallpaperHints" msgid="1153485176642032714">"ajustament de la mida del fons de pantalla"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index fd7b1b2ab55a..bb79c2193a36 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1633,7 +1633,7 @@ <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"निष्क्रिय"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> लाई तपाईंको यन्त्र पूर्ण रूपमा नियन्त्रण गर्न दिने हो?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"तपाईंले <xliff:g id="SERVICE">%1$s</xliff:g> सक्रिय गर्नुभयो भने तपाईंको यन्त्रले डेटा इन्क्रिप्ट गर्ने सुविधाको स्तरोन्नति गर्न तपाईंको स्क्रिन लक सुविधाको प्रयोग गर्ने छैन।"</string> - <string name="accessibility_service_warning_description" msgid="291674995220940133">"तपाईंलाई पहुँच राख्न आवश्यक पर्ने कुरामा सहयोग गर्ने अनुप्रयोगहरूमाथि पूर्ण नियन्त्रण गर्नु उपयुक्त हुन्छ तर अधिकांश अनुप्रयोगहरूका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string> + <string name="accessibility_service_warning_description" msgid="291674995220940133">"तपाईंलाई पहुँच राख्न आवश्यक पर्ने कुरामा सहयोग गर्ने एपमाथि पूर्ण नियन्त्रण गर्नु उपयुक्त हुन्छ तर अधिकांश अनुप्रयोगहरूका हकमा यस्तो नियन्त्रण उपयुक्त हुँदैन।"</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"स्क्रिन हेर्नुहोस् र नियन्त्रण गर्नुहोस्"</string> <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"यसले स्क्रिनमा देखिने सबै सामग्री पढ्न सक्छ र अन्य एपहरूमा उक्त सामग्री देखाउन सक्छ।"</string> <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"कारबाहीहरू हेर्नुहोस् र तिनमा कार्य गर्नुहोस्"</string> diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml index 3a1679c19fc8..f46f70c2debf 100644 --- a/core/res/res/values/donottranslate.xml +++ b/core/res/res/values/donottranslate.xml @@ -23,7 +23,7 @@ <!-- @hide DO NOT TRANSLATE. Control aspect ratio of lock pattern --> <string name="lock_pattern_view_aspect">square</string> <!-- @hide DO NOT TRANSLATE. ICU pattern for "Mon, 14 January" --> - <string name="icu_abbrev_wday_month_day_no_year">eeeMMMMd</string> + <string name="icu_abbrev_wday_month_day_no_year">EEEMMMMd</string> <!-- @hide DO NOT TRANSLATE. date formatting pattern for system ui.--> <string name="system_ui_date_pattern">@string/icu_abbrev_wday_month_day_no_year</string> <!-- @hide DO NOT TRANSLATE Spans within this text are applied to style composing regions diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index bddda1bf6f6f..f77c6f99c063 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -197,6 +197,9 @@ <!-- Marks the "copy to clipboard" button in the ChooserActivity --> <item type="id" name="chooser_copy_button" /> + <!-- Marks the "nearby" button in the ChooserActivity --> + <item type="id" name="chooser_nearby_button" /> + <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK}. --> <item type="id" name="accessibilitySystemActionBack" /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d5c72da2d29f..040fad5e6410 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3841,6 +3841,7 @@ <java-symbol type="layout" name="chooser_dialog_item" /> <java-symbol type="drawable" name="chooser_dialog_background" /> <java-symbol type="id" name="chooser_copy_button" /> + <java-symbol type="id" name="chooser_nearby_button" /> <java-symbol type="layout" name="chooser_action_button" /> <java-symbol type="dimen" name="chooser_action_button_icon_size" /> <java-symbol type="string" name="config_defaultNearbySharingComponent" /> diff --git a/core/tests/coretests/src/android/app/WindowContextTest.java b/core/tests/coretests/src/android/app/WindowContextTest.java index 630e16ac80d4..0f9bc4bee99a 100644 --- a/core/tests/coretests/src/android/app/WindowContextTest.java +++ b/core/tests/coretests/src/android/app/WindowContextTest.java @@ -30,7 +30,6 @@ import android.view.Display; import android.view.IWindowManager; import android.view.WindowManagerGlobal; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -47,7 +46,6 @@ import org.junit.runner.RunWith; * <p>This test class is a part of Window Manager Service tests and specified in * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ -@FlakyTest(bugId = 150812449, detail = "Remove after confirmed it's stable.") @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java index ddc977d380ae..96df9dda23c7 100644 --- a/core/tests/coretests/src/android/view/WindowMetricsTest.java +++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java @@ -27,7 +27,6 @@ import android.hardware.display.DisplayManager; import android.os.Handler; import android.platform.test.annotations.Presubmit; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -46,7 +45,6 @@ import org.junit.runner.RunWith; * <p>This test class is a part of Window Manager Service tests and specified in * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}. */ -@FlakyTest(bugId = 148789183, detail = "Remove after confirmed it's stable.") @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index 090645f6f7a8..787879a6a144 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -590,6 +590,54 @@ public class ChooserActivityTest { is(1)); } + + @Test + public void testNearbyShareLogging() throws Exception { + Intent sendIntent = createSendTextIntent(); + List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); + + when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent( + Mockito.anyBoolean(), + Mockito.anyBoolean(), + Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); + + final ChooserWrapperActivity activity = mActivityRule + .launchActivity(Intent.createChooser(sendIntent, null)); + waitForIdle(); + + onView(withId(R.id.chooser_nearby_button)).check(matches(isDisplayed())); + onView(withId(R.id.chooser_nearby_button)).perform(click()); + + ChooserActivityLoggerFake logger = + (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); + assertThat(logger.numCalls(), is(6)); + // first one should be SHARESHEET_TRIGGERED uievent + assertThat(logger.get(0).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); + assertThat(logger.get(0).event.getId(), + is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); + // second one should be SHARESHEET_STARTED event + assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); + assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); + assertThat(logger.get(1).mimeType, is("text/plain")); + assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).appProvidedApp, is(0)); + assertThat(logger.get(1).appProvidedDirect, is(0)); + assertThat(logger.get(1).isWorkprofile, is(false)); + assertThat(logger.get(1).previewType, is(3)); + // third one should be SHARESHEET_APP_LOAD_COMPLETE uievent + assertThat(logger.get(2).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); + assertThat(logger.get(2).event.getId(), + is(ChooserActivityLogger + .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); + // fourth and fifth are just artifacts of test set-up + // sixth one should be ranking atom with SHARESHEET_NEARBY_TARGET_SELECTED event + assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); + assertThat(logger.get(5).targetType, + is(ChooserActivityLogger + .SharesheetTargetSelectedEvent.SHARESHEET_NEARBY_TARGET_SELECTED.getId())); + } + + @Test public void oneVisibleImagePreview() throws InterruptedException { Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/" diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index d3d5caf3f7e2..16a2fbd6465e 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import android.annotation.Nullable; import android.app.usage.UsageStatsManager; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -89,6 +90,18 @@ public class ChooserWrapperActivity extends ChooserActivity { boolean getIsSelected() { return mIsSuccessfullySelected; } + @Override + protected ComponentName getNearbySharingComponent() { + // an arbitrary pre-installed activity that handles this type of intent + return ComponentName.unflattenFromString("com.google.android.apps.messaging/" + + "com.google.android.apps.messaging.ui.conversationlist.ShareIntentActivity"); + } + + @Override + protected TargetInfo getNearbySharingTarget(Intent originalIntent) { + return new ChooserWrapperActivity.EmptyTargetInfo(); + } + UsageStatsManager getUsageStatsManager() { if (mUsm == null) { mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE); diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index 188ba9e0ca0e..96250db4aa51 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.os.Binder; import android.os.Handler; @@ -44,6 +45,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Random; @@ -493,7 +495,9 @@ public class BinderCallsStatsTest { bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); PrintWriter pw = new PrintWriter(new StringWriter()); - bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), true); + bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), Process.INVALID_UID, true); + + bcs.dump(pw, new AppIdToPackageMap(new HashMap<>()), WORKSOURCE_UID, true); } @Test @@ -606,8 +610,8 @@ public class BinderCallsStatsTest { assertEquals("-1", callStats.methodName); assertEquals("com.android.internal.os.BinderCallsStats$OverflowBinder", callStats.className); - assertEquals(false , callStats.screenInteractive); - assertEquals(-1 , callStats.callingUid); + assertEquals(false, callStats.screenInteractive); + assertEquals(-1, callStats.callingUid); } @Test @@ -785,7 +789,7 @@ public class BinderCallsStatsTest { bcs.time += 30; bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); - for (Runnable runnable: mHandler.mRunnables) { + for (Runnable runnable : mHandler.mRunnables) { // Execute all pending runnables. Ignore the delay. runnable.run(); } @@ -839,6 +843,53 @@ public class BinderCallsStatsTest { assertEquals(3, tids[2]); } + @Test + public void testTrackingSpecificWorksourceUid() { + mDeviceState.setCharging(true); + + Binder binder = new Binder(); + + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.recordAllCallsForWorkSourceUid(WORKSOURCE_UID); + + int[] transactions = {41, 42, 43, 42, 43, 43}; + int[] durationsMs = {100, 200, 300, 400, 500, 600}; + + for (int i = 0; i < transactions.length; i++) { + CallSession callSession = bcs.callStarted(binder, transactions[i], WORKSOURCE_UID); + bcs.time += durationsMs[i]; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID); + } + + BinderCallsStats.UidEntry uidEntry = bcs.getUidEntries().get(WORKSOURCE_UID); + Assert.assertNotNull(uidEntry); + assertEquals(6, uidEntry.callCount); + + Collection<BinderCallsStats.CallStat> callStatsList = uidEntry.getCallStatsList(); + assertEquals(3, callStatsList.size()); + for (BinderCallsStats.CallStat callStat : callStatsList) { + switch (callStat.transactionCode) { + case 41: + assertEquals(1, callStat.callCount); + assertEquals(1, callStat.incrementalCallCount); + assertEquals(100, callStat.cpuTimeMicros); + break; + case 42: + assertEquals(2, callStat.callCount); + assertEquals(2, callStat.incrementalCallCount); + assertEquals(200 + 400, callStat.cpuTimeMicros); + break; + case 43: + assertEquals(3, callStat.callCount); + assertEquals(3, callStat.incrementalCallCount); + assertEquals(300 + 500 + 600, callStat.cpuTimeMicros); + break; + default: + fail("Unexpected transaction code: " + callStat.transactionCode); + } + } + } + private static class TestHandler extends Handler { ArrayList<Runnable> mRunnables = new ArrayList<>(); diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 5711f98e3b75..bd2d4af54c83 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -345,10 +345,10 @@ key 377 TV # key 395 "KEY_LIST" # key 396 "KEY_MEMO" key 397 CALENDAR -# key 398 "KEY_RED" -# key 399 "KEY_GREEN" -# key 400 "KEY_YELLOW" -# key 401 "KEY_BLUE" +key 398 PROG_RED +key 399 PROG_GREEN +key 400 PROG_YELLOW +key 401 PROG_BLUE key 402 CHANNEL_UP key 403 CHANNEL_DOWN # key 404 "KEY_FIRST" 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/OWNERS b/libs/hwui/OWNERS index 936ba5cc8311..c232d1360419 100644 --- a/libs/hwui/OWNERS +++ b/libs/hwui/OWNERS @@ -1,6 +1,7 @@ +alecmouri@google.com +djsollen@google.com jreck@google.com njawad@google.com -djsollen@google.com -stani@google.com -scroggo@google.com reed@google.com +scroggo@google.com +stani@google.com 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/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp index 644d5fbd5bf9..e4198017aee0 100644 --- a/libs/hwui/service/GraphicsStatsService.cpp +++ b/libs/hwui/service/GraphicsStatsService.cpp @@ -559,6 +559,7 @@ void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data, AStatsEvent_writeBool(event, !lastFullDay); AStatsEvent_build(event); } + delete dump; } 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/libs/input/Android.bp b/libs/input/Android.bp index 5252cd041199..dca35012cbdd 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -16,6 +16,9 @@ cc_library_shared { name: "libinputservice", srcs: [ "PointerController.cpp", + "PointerControllerContext.cpp", + "MouseCursorController.cpp", + "TouchSpotController.cpp", "SpriteController.cpp", "SpriteIcon.cpp", ], diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp new file mode 100644 index 000000000000..80b555be97dd --- /dev/null +++ b/libs/input/MouseCursorController.cpp @@ -0,0 +1,460 @@ +/* + * 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. + */ + +#define LOG_TAG "MouseCursorController" +//#define LOG_NDEBUG 0 + +// Log debug messages about pointer updates +#define DEBUG_MOUSE_CURSOR_UPDATES 0 + +#include "MouseCursorController.h" + +#include <log/log.h> + +#include <SkBitmap.h> +#include <SkBlendMode.h> +#include <SkCanvas.h> +#include <SkColor.h> +#include <SkPaint.h> + +namespace { +// Time to spend fading out the pointer completely. +const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms +} // namespace + +namespace android { + +// --- MouseCursorController --- + +MouseCursorController::MouseCursorController(PointerControllerContext& context) + : mContext(context) { + std::scoped_lock lock(mLock); + + mLocked.animationFrameIndex = 0; + mLocked.lastFrameUpdatedTime = 0; + + mLocked.pointerFadeDirection = 0; + mLocked.pointerX = 0; + mLocked.pointerY = 0; + mLocked.pointerAlpha = 0.0f; // pointer is initially faded + mLocked.pointerSprite = mContext.getSpriteController()->createSprite(); + mLocked.updatePointerIcon = false; + mLocked.requestedPointerType = mContext.getPolicy()->getDefaultPointerIconId(); + + mLocked.resourcesLoaded = false; + + mLocked.buttonState = 0; +} + +MouseCursorController::~MouseCursorController() { + std::scoped_lock lock(mLock); + + mLocked.pointerSprite.clear(); +} + +bool MouseCursorController::getBounds(float* outMinX, float* outMinY, float* outMaxX, + float* outMaxY) const { + std::scoped_lock lock(mLock); + + return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); +} + +bool MouseCursorController::getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, + float* outMaxY) const REQUIRES(mLock) { + if (!mLocked.viewport.isValid()) { + return false; + } + + *outMinX = mLocked.viewport.logicalLeft; + *outMinY = mLocked.viewport.logicalTop; + *outMaxX = mLocked.viewport.logicalRight - 1; + *outMaxY = mLocked.viewport.logicalBottom - 1; + return true; +} + +void MouseCursorController::move(float deltaX, float deltaY) { +#if DEBUG_MOUSE_CURSOR_UPDATES + ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); +#endif + if (deltaX == 0.0f && deltaY == 0.0f) { + return; + } + + std::scoped_lock lock(mLock); + + setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); +} + +void MouseCursorController::setButtonState(int32_t buttonState) { +#if DEBUG_MOUSE_CURSOR_UPDATES + ALOGD("Set button state 0x%08x", buttonState); +#endif + std::scoped_lock lock(mLock); + + if (mLocked.buttonState != buttonState) { + mLocked.buttonState = buttonState; + } +} + +int32_t MouseCursorController::getButtonState() const { + std::scoped_lock lock(mLock); + return mLocked.buttonState; +} + +void MouseCursorController::setPosition(float x, float y) { +#if DEBUG_MOUSE_CURSOR_UPDATES + ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); +#endif + std::scoped_lock lock(mLock); + setPositionLocked(x, y); +} + +void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) { + float minX, minY, maxX, maxY; + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { + if (x <= minX) { + mLocked.pointerX = minX; + } else if (x >= maxX) { + mLocked.pointerX = maxX; + } else { + mLocked.pointerX = x; + } + if (y <= minY) { + mLocked.pointerY = minY; + } else if (y >= maxY) { + mLocked.pointerY = maxY; + } else { + mLocked.pointerY = y; + } + updatePointerLocked(); + } +} + +void MouseCursorController::getPosition(float* outX, float* outY) const { + std::scoped_lock lock(mLock); + + *outX = mLocked.pointerX; + *outY = mLocked.pointerY; +} + +int32_t MouseCursorController::getDisplayId() const { + std::scoped_lock lock(mLock); + return mLocked.viewport.displayId; +} + +void MouseCursorController::fade(PointerControllerInterface::Transition transition) { + std::scoped_lock lock(mLock); + + // Remove the inactivity timeout, since we are fading now. + mContext.removeInactivityTimeout(); + + // Start fading. + if (transition == PointerControllerInterface::Transition::IMMEDIATE) { + mLocked.pointerFadeDirection = 0; + mLocked.pointerAlpha = 0.0f; + updatePointerLocked(); + } else { + mLocked.pointerFadeDirection = -1; + mContext.startAnimation(); + } +} + +void MouseCursorController::unfade(PointerControllerInterface::Transition transition) { + std::scoped_lock lock(mLock); + + // Always reset the inactivity timer. + mContext.resetInactivityTimeout(); + + // Start unfading. + if (transition == PointerControllerInterface::Transition::IMMEDIATE) { + mLocked.pointerFadeDirection = 0; + mLocked.pointerAlpha = 1.0f; + updatePointerLocked(); + } else { + mLocked.pointerFadeDirection = 1; + mContext.startAnimation(); + } +} + +void MouseCursorController::reloadPointerResources(bool getAdditionalMouseResources) { + std::scoped_lock lock(mLock); + + loadResourcesLocked(getAdditionalMouseResources); + updatePointerLocked(); +} + +/** + * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation, + * so here we are getting the dimensions in the original, unrotated orientation (orientation 0). + */ +static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) { + width = viewport.deviceWidth; + height = viewport.deviceHeight; + + if (viewport.orientation == DISPLAY_ORIENTATION_90 || + viewport.orientation == DISPLAY_ORIENTATION_270) { + std::swap(width, height); + } +} + +void MouseCursorController::setDisplayViewport(const DisplayViewport& viewport, + bool getAdditionalMouseResources) { + std::scoped_lock lock(mLock); + + if (viewport == mLocked.viewport) { + return; + } + + const DisplayViewport oldViewport = mLocked.viewport; + mLocked.viewport = viewport; + + int32_t oldDisplayWidth, oldDisplayHeight; + getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight); + int32_t newDisplayWidth, newDisplayHeight; + getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight); + + // Reset cursor position to center if size or display changed. + if (oldViewport.displayId != viewport.displayId || oldDisplayWidth != newDisplayWidth || + oldDisplayHeight != newDisplayHeight) { + float minX, minY, maxX, maxY; + if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { + mLocked.pointerX = (minX + maxX) * 0.5f; + mLocked.pointerY = (minY + maxY) * 0.5f; + // Reload icon resources for density may be changed. + loadResourcesLocked(getAdditionalMouseResources); + } else { + mLocked.pointerX = 0; + mLocked.pointerY = 0; + } + } else if (oldViewport.orientation != viewport.orientation) { + // Apply offsets to convert from the pixel top-left corner position to the pixel center. + // This creates an invariant frame of reference that we can easily rotate when + // taking into account that the pointer may be located at fractional pixel offsets. + float x = mLocked.pointerX + 0.5f; + float y = mLocked.pointerY + 0.5f; + float temp; + + // Undo the previous rotation. + switch (oldViewport.orientation) { + case DISPLAY_ORIENTATION_90: + temp = x; + x = oldViewport.deviceHeight - y; + y = temp; + break; + case DISPLAY_ORIENTATION_180: + x = oldViewport.deviceWidth - x; + y = oldViewport.deviceHeight - y; + break; + case DISPLAY_ORIENTATION_270: + temp = x; + x = y; + y = oldViewport.deviceWidth - temp; + break; + } + + // Perform the new rotation. + switch (viewport.orientation) { + case DISPLAY_ORIENTATION_90: + temp = x; + x = y; + y = viewport.deviceHeight - temp; + break; + case DISPLAY_ORIENTATION_180: + x = viewport.deviceWidth - x; + y = viewport.deviceHeight - y; + break; + case DISPLAY_ORIENTATION_270: + temp = x; + x = viewport.deviceWidth - y; + y = temp; + break; + } + + // Apply offsets to convert from the pixel center to the pixel top-left corner position + // and save the results. + mLocked.pointerX = x - 0.5f; + mLocked.pointerY = y - 0.5f; + } + + updatePointerLocked(); +} + +void MouseCursorController::updatePointerIcon(int32_t iconId) { + std::scoped_lock lock(mLock); + + if (mLocked.requestedPointerType != iconId) { + mLocked.requestedPointerType = iconId; + mLocked.updatePointerIcon = true; + updatePointerLocked(); + } +} + +void MouseCursorController::setCustomPointerIcon(const SpriteIcon& icon) { + std::scoped_lock lock(mLock); + + const int32_t iconId = mContext.getPolicy()->getCustomPointerIconId(); + mLocked.additionalMouseResources[iconId] = icon; + mLocked.requestedPointerType = iconId; + mLocked.updatePointerIcon = true; + updatePointerLocked(); +} + +bool MouseCursorController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) { + nsecs_t frameDelay = timestamp - mContext.getAnimationTime(); + + std::scoped_lock lock(mLock); + + // Animate pointer fade. + if (mLocked.pointerFadeDirection < 0) { + mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; + if (mLocked.pointerAlpha <= 0.0f) { + mLocked.pointerAlpha = 0.0f; + mLocked.pointerFadeDirection = 0; + } else { + keepAnimating = true; + } + updatePointerLocked(); + } else if (mLocked.pointerFadeDirection > 0) { + mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; + if (mLocked.pointerAlpha >= 1.0f) { + mLocked.pointerAlpha = 1.0f; + mLocked.pointerFadeDirection = 0; + } else { + keepAnimating = true; + } + updatePointerLocked(); + } + + return keepAnimating; +} + +bool MouseCursorController::doBitmapAnimation(nsecs_t timestamp) { + std::scoped_lock lock(mLock); + + std::map<int32_t, PointerAnimation>::const_iterator iter = + mLocked.animationResources.find(mLocked.requestedPointerType); + if (iter == mLocked.animationResources.end()) { + return false; + } + + if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) { + sp<SpriteController> spriteController = mContext.getSpriteController(); + spriteController->openTransaction(); + + int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame; + mLocked.animationFrameIndex += incr; + mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr; + while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) { + mLocked.animationFrameIndex -= iter->second.animationFrames.size(); + } + mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]); + + spriteController->closeTransaction(); + } + + // Keep animating. + return true; +} + +void MouseCursorController::updatePointerLocked() REQUIRES(mLock) { + if (!mLocked.viewport.isValid()) { + return; + } + sp<SpriteController> spriteController = mContext.getSpriteController(); + spriteController->openTransaction(); + + mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); + mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); + mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId); + + if (mLocked.pointerAlpha > 0) { + mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); + mLocked.pointerSprite->setVisible(true); + } else { + mLocked.pointerSprite->setVisible(false); + } + + if (mLocked.updatePointerIcon) { + if (mLocked.requestedPointerType == mContext.getPolicy()->getDefaultPointerIconId()) { + mLocked.pointerSprite->setIcon(mLocked.pointerIcon); + } else { + std::map<int32_t, SpriteIcon>::const_iterator iter = + mLocked.additionalMouseResources.find(mLocked.requestedPointerType); + if (iter != mLocked.additionalMouseResources.end()) { + std::map<int32_t, PointerAnimation>::const_iterator anim_iter = + mLocked.animationResources.find(mLocked.requestedPointerType); + if (anim_iter != mLocked.animationResources.end()) { + mLocked.animationFrameIndex = 0; + mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC); + mContext.startAnimation(); + } + mLocked.pointerSprite->setIcon(iter->second); + } else { + ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType); + mLocked.pointerSprite->setIcon(mLocked.pointerIcon); + } + } + mLocked.updatePointerIcon = false; + } + + spriteController->closeTransaction(); +} + +void MouseCursorController::loadResourcesLocked(bool getAdditionalMouseResources) REQUIRES(mLock) { + if (!mLocked.viewport.isValid()) { + return; + } + + if (!mLocked.resourcesLoaded) mLocked.resourcesLoaded = true; + + sp<PointerControllerPolicyInterface> policy = mContext.getPolicy(); + policy->loadPointerResources(&mResources, mLocked.viewport.displayId); + policy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId); + + mLocked.additionalMouseResources.clear(); + mLocked.animationResources.clear(); + if (getAdditionalMouseResources) { + policy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, + &mLocked.animationResources, + mLocked.viewport.displayId); + } + + mLocked.updatePointerIcon = true; +} + +bool MouseCursorController::isViewportValid() { + std::scoped_lock lock(mLock); + return mLocked.viewport.isValid(); +} + +void MouseCursorController::getAdditionalMouseResources() { + std::scoped_lock lock(mLock); + + if (mLocked.additionalMouseResources.empty()) { + mContext.getPolicy()->loadAdditionalMouseResources(&mLocked.additionalMouseResources, + &mLocked.animationResources, + mLocked.viewport.displayId); + } + mLocked.updatePointerIcon = true; + updatePointerLocked(); +} + +bool MouseCursorController::resourcesLoaded() { + std::scoped_lock lock(mLock); + return mLocked.resourcesLoaded; +} + +} // namespace android diff --git a/libs/input/MouseCursorController.h b/libs/input/MouseCursorController.h new file mode 100644 index 000000000000..448165b5ac46 --- /dev/null +++ b/libs/input/MouseCursorController.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_MOUSE_CURSOR_CONTROLLER_H +#define _UI_MOUSE_CURSOR_CONTROLLER_H + +#include <gui/DisplayEventReceiver.h> +#include <input/DisplayViewport.h> +#include <input/Input.h> +#include <ui/DisplayInfo.h> +#include <utils/BitSet.h> +#include <utils/Looper.h> +#include <utils/RefBase.h> + +#include <map> +#include <memory> +#include <vector> + +#include "PointerControllerContext.h" +#include "SpriteController.h" + +namespace android { + +/* + * Helper class for PointerController that specifically handles + * mouse cursor resources and actions. + */ +class MouseCursorController { +public: + MouseCursorController(PointerControllerContext& context); + ~MouseCursorController(); + + bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + void move(float deltaX, float deltaY); + void setButtonState(int32_t buttonState); + int32_t getButtonState() const; + void setPosition(float x, float y); + void getPosition(float* outX, float* outY) const; + int32_t getDisplayId() const; + void fade(PointerControllerInterface::Transition transition); + void unfade(PointerControllerInterface::Transition transition); + void setDisplayViewport(const DisplayViewport& viewport, bool getAdditionalMouseResources); + + void updatePointerIcon(int32_t iconId); + void setCustomPointerIcon(const SpriteIcon& icon); + void reloadPointerResources(bool getAdditionalMouseResources); + + void getAdditionalMouseResources(); + bool isViewportValid(); + + bool doBitmapAnimation(nsecs_t timestamp); + bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating); + + bool resourcesLoaded(); + +private: + mutable std::mutex mLock; + + PointerResources mResources; + + PointerControllerContext& mContext; + + struct Locked { + DisplayViewport viewport; + + size_t animationFrameIndex; + nsecs_t lastFrameUpdatedTime; + + int32_t pointerFadeDirection; + float pointerX; + float pointerY; + float pointerAlpha; + sp<Sprite> pointerSprite; + SpriteIcon pointerIcon; + bool updatePointerIcon; + + bool resourcesLoaded; + + std::map<int32_t, SpriteIcon> additionalMouseResources; + std::map<int32_t, PointerAnimation> animationResources; + + int32_t requestedPointerType; + + int32_t buttonState; + + } mLocked GUARDED_BY(mLock); + + bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; + void setPositionLocked(float x, float y); + + void updatePointerLocked(); + + void loadResourcesLocked(bool getAdditionalMouseResources); +}; + +} // namespace android + +#endif // _UI_MOUSE_CURSOR_CONTROLLER_H diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index 5e480a66c355..14c96cefd462 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -21,31 +21,26 @@ #define DEBUG_POINTER_UPDATES 0 #include "PointerController.h" +#include "MouseCursorController.h" +#include "PointerControllerContext.h" +#include "TouchSpotController.h" #include <log/log.h> -#include <memory> +#include <SkBitmap.h> +#include <SkBlendMode.h> +#include <SkCanvas.h> +#include <SkColor.h> +#include <SkPaint.h> namespace android { // --- PointerController --- -// Time to wait before starting the fade when the pointer is inactive. -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds - -// Time to spend fading out the spot completely. -static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms - -// Time to spend fading out the pointer completely. -static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms - -// The number of events to be read at once for DisplayEventReceiver. -static const int EVENT_BUFFER_SIZE = 100; - std::shared_ptr<PointerController> PointerController::create( const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper, const sp<SpriteController>& spriteController) { + // using 'new' to access non-public constructor std::shared_ptr<PointerController> controller = std::shared_ptr<PointerController>( new PointerController(policy, looper, spriteController)); @@ -60,758 +55,175 @@ std::shared_ptr<PointerController> PointerController::create( * weak_ptr's which themselves cannot be constructed until there's at least one shared_ptr. */ - controller->mHandler->pointerController = controller; - controller->mCallback->pointerController = controller; - if (controller->mDisplayEventReceiver.initCheck() == NO_ERROR) { - controller->mLooper->addFd(controller->mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, - Looper::EVENT_INPUT, controller->mCallback, nullptr); - } else { - ALOGE("Failed to initialize DisplayEventReceiver."); - } + controller->mContext.setHandlerController(controller); + controller->mContext.setCallbackController(controller); + controller->mContext.initializeDisplayEventReceiver(); return controller; } PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper, const sp<SpriteController>& spriteController) - : mPolicy(policy), - mLooper(looper), - mSpriteController(spriteController), - mHandler(new MessageHandler()), - mCallback(new LooperCallback()) { - AutoMutex _l(mLock); - - mLocked.animationPending = false; - - mLocked.presentation = Presentation::POINTER; - mLocked.presentationChanged = false; - - mLocked.inactivityTimeout = InactivityTimeout::NORMAL; - - mLocked.pointerFadeDirection = 0; - mLocked.pointerX = 0; - mLocked.pointerY = 0; - mLocked.pointerAlpha = 0.0f; // pointer is initially faded - mLocked.pointerSprite = mSpriteController->createSprite(); - mLocked.pointerIconChanged = false; - mLocked.requestedPointerType = mPolicy->getDefaultPointerIconId(); - - mLocked.animationFrameIndex = 0; - mLocked.lastFrameUpdatedTime = 0; - - mLocked.buttonState = 0; + : mContext(policy, looper, spriteController, *this), mCursorController(mContext) { + std::scoped_lock lock(mLock); + mLocked.presentation = Presentation::SPOT; } -PointerController::~PointerController() { - mLooper->removeMessages(mHandler); - - AutoMutex _l(mLock); - - mLocked.pointerSprite.clear(); - - for (auto& it : mLocked.spotsByDisplay) { - const std::vector<Spot*>& spots = it.second; - size_t numSpots = spots.size(); - for (size_t i = 0; i < numSpots; i++) { - delete spots[i]; - } - } - mLocked.spotsByDisplay.clear(); - mLocked.recycledSprites.clear(); -} - -bool PointerController::getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - AutoMutex _l(mLock); - - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); -} - -bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - - if (!mLocked.viewport.isValid()) { - return false; - } - - *outMinX = mLocked.viewport.logicalLeft; - *outMinY = mLocked.viewport.logicalTop; - *outMaxX = mLocked.viewport.logicalRight - 1; - *outMaxY = mLocked.viewport.logicalBottom - 1; - return true; +bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX, + float* outMaxY) const { + return mCursorController.getBounds(outMinX, outMinY, outMaxX, outMaxY); } void PointerController::move(float deltaX, float deltaY) { -#if DEBUG_POINTER_UPDATES - ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); -#endif - if (deltaX == 0.0f && deltaY == 0.0f) { - return; - } - - AutoMutex _l(mLock); - - setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); + mCursorController.move(deltaX, deltaY); } void PointerController::setButtonState(int32_t buttonState) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set button state 0x%08x", buttonState); -#endif - AutoMutex _l(mLock); - - if (mLocked.buttonState != buttonState) { - mLocked.buttonState = buttonState; - } + mCursorController.setButtonState(buttonState); } int32_t PointerController::getButtonState() const { - AutoMutex _l(mLock); - - return mLocked.buttonState; + return mCursorController.getButtonState(); } void PointerController::setPosition(float x, float y) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); -#endif - AutoMutex _l(mLock); - - setPositionLocked(x, y); -} - -void PointerController::setPositionLocked(float x, float y) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } + std::scoped_lock lock(mLock); + mCursorController.setPosition(x, y); } void PointerController::getPosition(float* outX, float* outY) const { - AutoMutex _l(mLock); - - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; + mCursorController.getPosition(outX, outY); } int32_t PointerController::getDisplayId() const { - AutoMutex _l(mLock); - - return mLocked.viewport.displayId; + return mCursorController.getDisplayId(); } void PointerController::fade(Transition transition) { - AutoMutex _l(mLock); - - // Remove the inactivity timeout, since we are fading now. - removeInactivityTimeoutLocked(); - - // Start fading. - if (transition == Transition::IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 0.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = -1; - startAnimationLocked(); - } + std::scoped_lock lock(mLock); + mCursorController.fade(transition); } void PointerController::unfade(Transition transition) { - AutoMutex _l(mLock); - - // Always reset the inactivity timer. - resetInactivityTimeoutLocked(); - - // Start unfading. - if (transition == Transition::IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 1.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = 1; - startAnimationLocked(); - } + std::scoped_lock lock(mLock); + mCursorController.unfade(transition); } void PointerController::setPresentation(Presentation presentation) { - AutoMutex _l(mLock); + std::scoped_lock lock(mLock); if (mLocked.presentation == presentation) { return; } mLocked.presentation = presentation; - mLocked.presentationChanged = true; - if (!mLocked.viewport.isValid()) { + if (!mCursorController.isViewportValid()) { return; } if (presentation == Presentation::POINTER) { - if (mLocked.additionalMouseResources.empty()) { - mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources, - mLocked.viewport.displayId); - } - fadeOutAndReleaseAllSpotsLocked(); - updatePointerLocked(); + mCursorController.getAdditionalMouseResources(); + clearSpotsLocked(); } } -void PointerController::setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId) { -#if DEBUG_POINTER_UPDATES - ALOGD("setSpots: idBits=%08x", spotIdBits.value); - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id, - c.getAxisValue(AMOTION_EVENT_AXIS_X), - c.getAxisValue(AMOTION_EVENT_AXIS_Y), - c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - displayId); +void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId) { + std::scoped_lock lock(mLock); + auto it = mLocked.spotControllers.find(displayId); + if (it == mLocked.spotControllers.end()) { + mLocked.spotControllers.try_emplace(displayId, displayId, mContext); } -#endif - - AutoMutex _l(mLock); - if (!mLocked.viewport.isValid()) { - return; - } - - std::vector<Spot*> newSpots; - std::map<int32_t, std::vector<Spot*>>::const_iterator iter = - mLocked.spotsByDisplay.find(displayId); - if (iter != mLocked.spotsByDisplay.end()) { - newSpots = iter->second; - } - - mSpriteController->openTransaction(); - - // Add or move spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 - ? mResources.spotTouch : mResources.spotHover; - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - - Spot* spot = getSpot(id, newSpots); - if (!spot) { - spot = createAndAddSpotLocked(id, newSpots); - } - - spot->updateSprite(&icon, x, y, displayId); - } - - // Remove spots for fingers that went up. - for (size_t i = 0; i < newSpots.size(); i++) { - Spot* spot = newSpots[i]; - if (spot->id != Spot::INVALID_ID - && !spotIdBits.hasBit(spot->id)) { - fadeOutAndReleaseSpotLocked(spot); - } - } - - mSpriteController->closeTransaction(); - mLocked.spotsByDisplay[displayId] = newSpots; + mLocked.spotControllers.at(displayId).setSpots(spotCoords, spotIdToIndex, spotIdBits); } void PointerController::clearSpots() { -#if DEBUG_POINTER_UPDATES - ALOGD("clearSpots"); -#endif + std::scoped_lock lock(mLock); + clearSpotsLocked(); +} - AutoMutex _l(mLock); - if (!mLocked.viewport.isValid()) { - return; +void PointerController::clearSpotsLocked() REQUIRES(mLock) { + for (auto& [displayID, spotController] : mLocked.spotControllers) { + spotController.clearSpots(); } - - fadeOutAndReleaseAllSpotsLocked(); } void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { - AutoMutex _l(mLock); - - if (mLocked.inactivityTimeout != inactivityTimeout) { - mLocked.inactivityTimeout = inactivityTimeout; - resetInactivityTimeoutLocked(); - } + mContext.setInactivityTimeout(inactivityTimeout); } void PointerController::reloadPointerResources() { - AutoMutex _l(mLock); + std::scoped_lock lock(mLock); - loadResourcesLocked(); - updatePointerLocked(); -} - -/** - * The viewport values for deviceHeight and deviceWidth have already been adjusted for rotation, - * so here we are getting the dimensions in the original, unrotated orientation (orientation 0). - */ -static void getNonRotatedSize(const DisplayViewport& viewport, int32_t& width, int32_t& height) { - width = viewport.deviceWidth; - height = viewport.deviceHeight; + for (auto& [displayID, spotController] : mLocked.spotControllers) { + spotController.reloadSpotResources(); + } - if (viewport.orientation == DISPLAY_ORIENTATION_90 - || viewport.orientation == DISPLAY_ORIENTATION_270) { - std::swap(width, height); + if (mCursorController.resourcesLoaded()) { + bool getAdditionalMouseResources = false; + if (mLocked.presentation == PointerController::Presentation::POINTER) { + getAdditionalMouseResources = true; + } + mCursorController.reloadPointerResources(getAdditionalMouseResources); } } void PointerController::setDisplayViewport(const DisplayViewport& viewport) { - AutoMutex _l(mLock); - if (viewport == mLocked.viewport) { - return; - } - - const DisplayViewport oldViewport = mLocked.viewport; - mLocked.viewport = viewport; - - int32_t oldDisplayWidth, oldDisplayHeight; - getNonRotatedSize(oldViewport, oldDisplayWidth, oldDisplayHeight); - int32_t newDisplayWidth, newDisplayHeight; - getNonRotatedSize(viewport, newDisplayWidth, newDisplayHeight); - - // Reset cursor position to center if size or display changed. - if (oldViewport.displayId != viewport.displayId - || oldDisplayWidth != newDisplayWidth - || oldDisplayHeight != newDisplayHeight) { - - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; - // Reload icon resources for density may be changed. - loadResourcesLocked(); - } else { - mLocked.pointerX = 0; - mLocked.pointerY = 0; - } + std::scoped_lock lock(mLock); - fadeOutAndReleaseAllSpotsLocked(); - } else if (oldViewport.orientation != viewport.orientation) { - // Apply offsets to convert from the pixel top-left corner position to the pixel center. - // This creates an invariant frame of reference that we can easily rotate when - // taking into account that the pointer may be located at fractional pixel offsets. - float x = mLocked.pointerX + 0.5f; - float y = mLocked.pointerY + 0.5f; - float temp; - - // Undo the previous rotation. - switch (oldViewport.orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = oldViewport.deviceHeight - y; - y = temp; - break; - case DISPLAY_ORIENTATION_180: - x = oldViewport.deviceWidth - x; - y = oldViewport.deviceHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = y; - y = oldViewport.deviceWidth - temp; - break; - } - - // Perform the new rotation. - switch (viewport.orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = y; - y = viewport.deviceHeight - temp; - break; - case DISPLAY_ORIENTATION_180: - x = viewport.deviceWidth - x; - y = viewport.deviceHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = viewport.deviceWidth - y; - y = temp; - break; - } - - // Apply offsets to convert from the pixel center to the pixel top-left corner position - // and save the results. - mLocked.pointerX = x - 0.5f; - mLocked.pointerY = y - 0.5f; + bool getAdditionalMouseResources = false; + if (mLocked.presentation == PointerController::Presentation::POINTER) { + getAdditionalMouseResources = true; } - - updatePointerLocked(); + mCursorController.setDisplayViewport(viewport, getAdditionalMouseResources); } void PointerController::updatePointerIcon(int32_t iconId) { - AutoMutex _l(mLock); - if (mLocked.requestedPointerType != iconId) { - mLocked.requestedPointerType = iconId; - mLocked.presentationChanged = true; - updatePointerLocked(); - } + std::scoped_lock lock(mLock); + mCursorController.updatePointerIcon(iconId); } void PointerController::setCustomPointerIcon(const SpriteIcon& icon) { - AutoMutex _l(mLock); - - const int32_t iconId = mPolicy->getCustomPointerIconId(); - mLocked.additionalMouseResources[iconId] = icon; - mLocked.requestedPointerType = iconId; - mLocked.presentationChanged = true; - - updatePointerLocked(); -} - -void PointerController::MessageHandler::handleMessage(const Message& message) { - std::shared_ptr<PointerController> controller = pointerController.lock(); - - if (controller == nullptr) { - ALOGE("PointerController instance was released before processing message: what=%d", - message.what); - return; - } - switch (message.what) { - case MSG_INACTIVITY_TIMEOUT: - controller->doInactivityTimeout(); - break; - } -} - -int PointerController::LooperCallback::handleEvent(int /* fd */, int events, void* /* data */) { - std::shared_ptr<PointerController> controller = pointerController.lock(); - if (controller == nullptr) { - ALOGW("PointerController instance was released with pending callbacks. events=0x%x", - events); - return 0; // Remove the callback, the PointerController is gone anyways - } - if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { - ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events); - return 0; // remove the callback - } - - if (!(events & Looper::EVENT_INPUT)) { - ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events); - return 1; // keep the callback - } - - bool gotVsync = false; - ssize_t n; - nsecs_t timestamp; - DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; - while ((n = controller->mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { - for (size_t i = 0; i < static_cast<size_t>(n); ++i) { - if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - timestamp = buf[i].header.timestamp; - gotVsync = true; - } - } - } - if (gotVsync) { - controller->doAnimate(timestamp); - } - return 1; // keep the callback + std::scoped_lock lock(mLock); + mCursorController.setCustomPointerIcon(icon); } void PointerController::doAnimate(nsecs_t timestamp) { - AutoMutex _l(mLock); - - mLocked.animationPending = false; + std::scoped_lock lock(mLock); - bool keepFading = doFadingAnimationLocked(timestamp); - bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp); - if (keepFading || keepBitmapFlipping) { - startAnimationLocked(); - } -} + mContext.setAnimationPending(false); -bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) { - bool keepAnimating = false; - nsecs_t frameDelay = timestamp - mLocked.animationTime; + bool keepFading = false; + keepFading = mCursorController.doFadingAnimation(timestamp, keepFading); - // Animate pointer fade. - if (mLocked.pointerFadeDirection < 0) { - mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha <= 0.0f) { - mLocked.pointerAlpha = 0.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } else if (mLocked.pointerFadeDirection > 0) { - mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha >= 1.0f) { - mLocked.pointerAlpha = 1.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); + for (auto& [displayID, spotController] : mLocked.spotControllers) { + keepFading = spotController.doFadingAnimation(timestamp, keepFading); } - // Animate spots that are fading out and being removed. - for(auto it = mLocked.spotsByDisplay.begin(); it != mLocked.spotsByDisplay.end();) { - std::vector<Spot*>& spots = it->second; - size_t numSpots = spots.size(); - for (size_t i = 0; i < numSpots;) { - Spot* spot = spots[i]; - if (spot->id == Spot::INVALID_ID) { - spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; - if (spot->alpha <= 0) { - spots.erase(spots.begin() + i); - releaseSpotLocked(spot); - numSpots--; - continue; - } else { - spot->sprite->setAlpha(spot->alpha); - keepAnimating = true; - } - } - ++i; - } - - if (spots.size() == 0) { - it = mLocked.spotsByDisplay.erase(it); - } else { - ++it; - } - } - - return keepAnimating; -} - -bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) { - std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find( - mLocked.requestedPointerType); - if (iter == mLocked.animationResources.end()) { - return false; - } - - if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) { - mSpriteController->openTransaction(); - - int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame; - mLocked.animationFrameIndex += incr; - mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr; - while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) { - mLocked.animationFrameIndex -= iter->second.animationFrames.size(); - } - mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]); - - mSpriteController->closeTransaction(); + bool keepBitmapFlipping = mCursorController.doBitmapAnimation(timestamp); + if (keepFading || keepBitmapFlipping) { + mContext.startAnimation(); } - - // Keep animating. - return true; } void PointerController::doInactivityTimeout() { fade(Transition::GRADUAL); } -void PointerController::startAnimationLocked() { - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mDisplayEventReceiver.requestNextVsync(); - } -} - -void PointerController::resetInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); - - nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT - ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT - : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; - mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::removeInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::updatePointerLocked() REQUIRES(mLock) { - if (!mLocked.viewport.isValid()) { - return; - } - - mSpriteController->openTransaction(); - - mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); - mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); - mLocked.pointerSprite->setDisplayId(mLocked.viewport.displayId); - - if (mLocked.pointerAlpha > 0) { - mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); - mLocked.pointerSprite->setVisible(true); - } else { - mLocked.pointerSprite->setVisible(false); - } - - if (mLocked.pointerIconChanged || mLocked.presentationChanged) { - if (mLocked.presentation == Presentation::POINTER) { - if (mLocked.requestedPointerType == mPolicy->getDefaultPointerIconId()) { - mLocked.pointerSprite->setIcon(mLocked.pointerIcon); - } else { - std::map<int32_t, SpriteIcon>::const_iterator iter = - mLocked.additionalMouseResources.find(mLocked.requestedPointerType); - if (iter != mLocked.additionalMouseResources.end()) { - std::map<int32_t, PointerAnimation>::const_iterator anim_iter = - mLocked.animationResources.find(mLocked.requestedPointerType); - if (anim_iter != mLocked.animationResources.end()) { - mLocked.animationFrameIndex = 0; - mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC); - startAnimationLocked(); - } - mLocked.pointerSprite->setIcon(iter->second); - } else { - ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerType); - mLocked.pointerSprite->setIcon(mLocked.pointerIcon); - } - } - } else { - mLocked.pointerSprite->setIcon(mResources.spotAnchor); - } - mLocked.pointerIconChanged = false; - mLocked.presentationChanged = false; - } - - mSpriteController->closeTransaction(); -} - -PointerController::Spot* PointerController::getSpot(uint32_t id, const std::vector<Spot*>& spots) { - for (size_t i = 0; i < spots.size(); i++) { - Spot* spot = spots[i]; - if (spot->id == id) { - return spot; - } +void PointerController::onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports) { + std::unordered_set<int32_t> displayIdSet; + for (DisplayViewport viewport : viewports) { + displayIdSet.insert(viewport.displayId); } - return nullptr; -} - -PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id, - std::vector<Spot*>& spots) { - // Remove spots until we have fewer than MAX_SPOTS remaining. - while (spots.size() >= MAX_SPOTS) { - Spot* spot = removeFirstFadingSpotLocked(spots); - if (!spot) { - spot = spots[0]; - spots.erase(spots.begin()); - } - releaseSpotLocked(spot); - } - - // Obtain a sprite from the recycled pool. - sp<Sprite> sprite; - if (! mLocked.recycledSprites.empty()) { - sprite = mLocked.recycledSprites.back(); - mLocked.recycledSprites.pop_back(); - } else { - sprite = mSpriteController->createSprite(); - } - - // Return the new spot. - Spot* spot = new Spot(id, sprite); - spots.push_back(spot); - return spot; -} - -PointerController::Spot* PointerController::removeFirstFadingSpotLocked(std::vector<Spot*>& spots) { - for (size_t i = 0; i < spots.size(); i++) { - Spot* spot = spots[i]; - if (spot->id == Spot::INVALID_ID) { - spots.erase(spots.begin() + i); - return spot; - } - } - return nullptr; -} - -void PointerController::releaseSpotLocked(Spot* spot) { - spot->sprite->clearIcon(); - - if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { - mLocked.recycledSprites.push_back(spot->sprite); - } - - delete spot; -} - -void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { - if (spot->id != Spot::INVALID_ID) { - spot->id = Spot::INVALID_ID; - startAnimationLocked(); - } -} - -void PointerController::fadeOutAndReleaseAllSpotsLocked() { - for (auto& it : mLocked.spotsByDisplay) { - const std::vector<Spot*>& spots = it.second; - size_t numSpots = spots.size(); - for (size_t i = 0; i < numSpots; i++) { - Spot* spot = spots[i]; - fadeOutAndReleaseSpotLocked(spot); - } - } -} - -void PointerController::loadResourcesLocked() REQUIRES(mLock) { - if (!mLocked.viewport.isValid()) { - return; - } - - mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId); - mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId); - - mLocked.additionalMouseResources.clear(); - mLocked.animationResources.clear(); - if (mLocked.presentation == Presentation::POINTER) { - mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources, mLocked.viewport.displayId); - } - - mLocked.pointerIconChanged = true; -} - - -// --- PointerController::Spot --- - -void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y, - int32_t displayId) { - sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); - sprite->setAlpha(alpha); - sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); - sprite->setPosition(x, y); - sprite->setDisplayId(displayId); - this->x = x; - this->y = y; - - if (icon != lastIcon) { - lastIcon = icon; - if (icon) { - sprite->setIcon(*icon); - sprite->setVisible(true); + std::scoped_lock lock(mLock); + for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) { + int32_t displayID = it->first; + if (!displayIdSet.count(displayID)) { + it = mLocked.spotControllers.erase(it); } else { - sprite->setVisible(false); + ++it; } } } diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 14c0679654c6..1f561da333b1 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -30,48 +30,14 @@ #include <memory> #include <vector> +#include "MouseCursorController.h" +#include "PointerControllerContext.h" #include "SpriteController.h" +#include "TouchSpotController.h" namespace android { /* - * Pointer resources. - */ -struct PointerResources { - SpriteIcon spotHover; - SpriteIcon spotTouch; - SpriteIcon spotAnchor; -}; - -struct PointerAnimation { - std::vector<SpriteIcon> animationFrames; - nsecs_t durationPerFrame; -}; - -/* - * Pointer controller policy interface. - * - * The pointer controller policy is used by the pointer controller to interact with - * the Window Manager and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class PointerControllerPolicyInterface : public virtual RefBase { -protected: - PointerControllerPolicyInterface() { } - virtual ~PointerControllerPolicyInterface() { } - -public: - virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0; - virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0; - virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, - std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0; - virtual int32_t getDefaultPointerIconId() = 0; - virtual int32_t getCustomPointerIconId() = 0; -}; - -/* * Tracks pointer movements and draws the pointer sprite to a surface. * * Handles pointer acceleration and animation. @@ -81,15 +47,10 @@ public: static std::shared_ptr<PointerController> create( const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper, const sp<SpriteController>& spriteController); - enum class InactivityTimeout { - NORMAL = 0, - SHORT = 1, - }; - virtual ~PointerController(); + virtual ~PointerController() = default; - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; + virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; virtual void move(float deltaX, float deltaY); virtual void setButtonState(int32_t buttonState); virtual int32_t getButtonState() const; @@ -101,129 +62,37 @@ public: virtual void setDisplayViewport(const DisplayViewport& viewport); virtual void setPresentation(Presentation presentation); - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits, int32_t displayId); + virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits, int32_t displayId); virtual void clearSpots(); void updatePointerIcon(int32_t iconId); void setCustomPointerIcon(const SpriteIcon& icon); void setInactivityTimeout(InactivityTimeout inactivityTimeout); + void doInactivityTimeout(); + void doAnimate(nsecs_t timestamp); void reloadPointerResources(); + void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports); private: - static constexpr size_t MAX_RECYCLED_SPRITES = 12; - static constexpr size_t MAX_SPOTS = 12; - - enum { - MSG_INACTIVITY_TIMEOUT, - }; - - struct Spot { - static const uint32_t INVALID_ID = 0xffffffff; - - uint32_t id; - sp<Sprite> sprite; - float alpha; - float scale; - float x, y; - - inline Spot(uint32_t id, const sp<Sprite>& sprite) - : id(id), - sprite(sprite), - alpha(1.0f), - scale(1.0f), - x(0.0f), - y(0.0f), - lastIcon(nullptr) {} - - void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId); + friend PointerControllerContext::LooperCallback; + friend PointerControllerContext::MessageHandler; - private: - const SpriteIcon* lastIcon; - }; + mutable std::mutex mLock; - class MessageHandler : public virtual android::MessageHandler { - public: - void handleMessage(const Message& message) override; - std::weak_ptr<PointerController> pointerController; - }; + PointerControllerContext mContext; - class LooperCallback : public virtual android::LooperCallback { - public: - int handleEvent(int fd, int events, void* data) override; - std::weak_ptr<PointerController> pointerController; - }; - - mutable Mutex mLock; - - sp<PointerControllerPolicyInterface> mPolicy; - sp<Looper> mLooper; - sp<SpriteController> mSpriteController; - sp<MessageHandler> mHandler; - sp<LooperCallback> mCallback; - - DisplayEventReceiver mDisplayEventReceiver; - - PointerResources mResources; + MouseCursorController mCursorController; struct Locked { - bool animationPending; - nsecs_t animationTime; - - size_t animationFrameIndex; - nsecs_t lastFrameUpdatedTime; - - DisplayViewport viewport; - - InactivityTimeout inactivityTimeout; - Presentation presentation; - bool presentationChanged; - - int32_t pointerFadeDirection; - float pointerX; - float pointerY; - float pointerAlpha; - sp<Sprite> pointerSprite; - SpriteIcon pointerIcon; - bool pointerIconChanged; - - std::map<int32_t, SpriteIcon> additionalMouseResources; - std::map<int32_t, PointerAnimation> animationResources; - int32_t requestedPointerType; - - int32_t buttonState; - - std::map<int32_t /* displayId */, std::vector<Spot*>> spotsByDisplay; - std::vector<sp<Sprite>> recycledSprites; + std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers; } mLocked GUARDED_BY(mLock); PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper, const sp<SpriteController>& spriteController); - - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; - void setPositionLocked(float x, float y); - - void doAnimate(nsecs_t timestamp); - bool doFadingAnimationLocked(nsecs_t timestamp); - bool doBitmapAnimationLocked(nsecs_t timestamp); - void doInactivityTimeout(); - - void startAnimationLocked(); - - void resetInactivityTimeoutLocked(); - void removeInactivityTimeoutLocked(); - void updatePointerLocked(); - - Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots); - Spot* createAndAddSpotLocked(uint32_t id, std::vector<Spot*>& spots); - Spot* removeFirstFadingSpotLocked(std::vector<Spot*>& spots); - void releaseSpotLocked(Spot* spot); - void fadeOutAndReleaseSpotLocked(Spot* spot); - void fadeOutAndReleaseAllSpotsLocked(); - - void loadResourcesLocked(); + void clearSpotsLocked(); }; } // namespace android diff --git a/libs/input/PointerControllerContext.cpp b/libs/input/PointerControllerContext.cpp new file mode 100644 index 000000000000..2d7e22b01112 --- /dev/null +++ b/libs/input/PointerControllerContext.cpp @@ -0,0 +1,179 @@ +/* + * 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. + */ + +#include "PointerControllerContext.h" +#include "PointerController.h" + +namespace { +// Time to wait before starting the fade when the pointer is inactive. +const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds +const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds + +// The number of events to be read at once for DisplayEventReceiver. +const int EVENT_BUFFER_SIZE = 100; +} // namespace + +namespace android { + +// --- PointerControllerContext --- + +PointerControllerContext::PointerControllerContext( + const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper, + const sp<SpriteController>& spriteController, PointerController& controller) + : mPolicy(policy), + mLooper(looper), + mSpriteController(spriteController), + mHandler(new MessageHandler()), + mCallback(new LooperCallback()), + mController(controller) { + std::scoped_lock lock(mLock); + mLocked.inactivityTimeout = InactivityTimeout::NORMAL; + mLocked.animationPending = false; +} + +PointerControllerContext::~PointerControllerContext() { + mLooper->removeMessages(mHandler); +} + +void PointerControllerContext::setInactivityTimeout(InactivityTimeout inactivityTimeout) { + std::scoped_lock lock(mLock); + + if (mLocked.inactivityTimeout != inactivityTimeout) { + mLocked.inactivityTimeout = inactivityTimeout; + resetInactivityTimeoutLocked(); + } +} + +void PointerControllerContext::startAnimation() { + std::scoped_lock lock(mLock); + if (!mLocked.animationPending) { + mLocked.animationPending = true; + mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); + mDisplayEventReceiver.requestNextVsync(); + } +} + +void PointerControllerContext::resetInactivityTimeout() { + std::scoped_lock lock(mLock); + resetInactivityTimeoutLocked(); +} + +void PointerControllerContext::resetInactivityTimeoutLocked() REQUIRES(mLock) { + mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT); + + nsecs_t timeout = mLocked.inactivityTimeout == InactivityTimeout::SHORT + ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT + : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; + mLooper->sendMessageDelayed(timeout, mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT); +} + +void PointerControllerContext::removeInactivityTimeout() { + std::scoped_lock lock(mLock); + mLooper->removeMessages(mHandler, MessageHandler::MSG_INACTIVITY_TIMEOUT); +} + +void PointerControllerContext::setAnimationPending(bool animationPending) { + std::scoped_lock lock(mLock); + mLocked.animationPending = animationPending; +} + +nsecs_t PointerControllerContext::getAnimationTime() { + std::scoped_lock lock(mLock); + return mLocked.animationTime; +} + +void PointerControllerContext::setHandlerController(std::shared_ptr<PointerController> controller) { + mHandler->pointerController = controller; +} + +void PointerControllerContext::setCallbackController( + std::shared_ptr<PointerController> controller) { + mCallback->pointerController = controller; +} + +sp<PointerControllerPolicyInterface> PointerControllerContext::getPolicy() { + return mPolicy; +} + +sp<SpriteController> PointerControllerContext::getSpriteController() { + return mSpriteController; +} + +void PointerControllerContext::initializeDisplayEventReceiver() { + if (mDisplayEventReceiver.initCheck() == NO_ERROR) { + mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK, Looper::EVENT_INPUT, + mCallback, nullptr); + } else { + ALOGE("Failed to initialize DisplayEventReceiver."); + } +} + +void PointerControllerContext::handleDisplayEvents() { + bool gotVsync = false; + ssize_t n; + nsecs_t timestamp; + DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; + while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { + for (size_t i = 0; i < static_cast<size_t>(n); ++i) { + if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { + timestamp = buf[i].header.timestamp; + gotVsync = true; + } + } + } + if (gotVsync) { + mController.doAnimate(timestamp); + } +} + +void PointerControllerContext::MessageHandler::handleMessage(const Message& message) { + std::shared_ptr<PointerController> controller = pointerController.lock(); + + if (controller == nullptr) { + ALOGE("PointerController instance was released before processing message: what=%d", + message.what); + return; + } + switch (message.what) { + case MSG_INACTIVITY_TIMEOUT: + controller->doInactivityTimeout(); + break; + } +} + +int PointerControllerContext::LooperCallback::handleEvent(int /* fd */, int events, + void* /* data */) { + std::shared_ptr<PointerController> controller = pointerController.lock(); + if (controller == nullptr) { + ALOGW("PointerController instance was released with pending callbacks. events=0x%x", + events); + return 0; // Remove the callback, the PointerController is gone anyways + } + if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { + ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", events); + return 0; // remove the callback + } + + if (!(events & Looper::EVENT_INPUT)) { + ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events); + return 1; // keep the callback + } + + controller->mContext.handleDisplayEvents(); + return 1; // keep the callback +} + +} // namespace android diff --git a/libs/input/PointerControllerContext.h b/libs/input/PointerControllerContext.h new file mode 100644 index 000000000000..92e1bda25f56 --- /dev/null +++ b/libs/input/PointerControllerContext.h @@ -0,0 +1,154 @@ +/* + * 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. + */ + +#ifndef _UI_POINTER_CONTROLLER_CONTEXT_H +#define _UI_POINTER_CONTROLLER_CONTEXT_H + +#include <PointerControllerInterface.h> +#include <gui/DisplayEventReceiver.h> +#include <input/DisplayViewport.h> +#include <input/Input.h> +#include <ui/DisplayInfo.h> +#include <utils/BitSet.h> +#include <utils/Looper.h> +#include <utils/RefBase.h> + +#include <map> +#include <memory> +#include <vector> + +#include "SpriteController.h" + +namespace android { + +class PointerController; + +/* + * Pointer resources. + */ +struct PointerResources { + SpriteIcon spotHover; + SpriteIcon spotTouch; + SpriteIcon spotAnchor; +}; + +struct PointerAnimation { + std::vector<SpriteIcon> animationFrames; + nsecs_t durationPerFrame; +}; + +enum class InactivityTimeout { + NORMAL = 0, + SHORT = 1, +}; + +/* + * Pointer controller policy interface. + * + * The pointer controller policy is used by the pointer controller to interact with + * the Window Manager and other system components. + * + * The actual implementation is partially supported by callbacks into the DVM + * via JNI. This interface is also mocked in the unit tests. + */ +class PointerControllerPolicyInterface : public virtual RefBase { +protected: + PointerControllerPolicyInterface() {} + virtual ~PointerControllerPolicyInterface() {} + +public: + virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0; + virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0; + virtual void loadAdditionalMouseResources( + std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0; + virtual int32_t getDefaultPointerIconId() = 0; + virtual int32_t getCustomPointerIconId() = 0; +}; + +/* + * Contains logic and resources shared among PointerController, + * MouseCursorController, and TouchSpotController. + */ + +class PointerControllerContext { +public: + PointerControllerContext(const sp<PointerControllerPolicyInterface>& policy, + const sp<Looper>& looper, const sp<SpriteController>& spriteController, + PointerController& controller); + ~PointerControllerContext(); + + void removeInactivityTimeout(); + void resetInactivityTimeout(); + void startAnimation(); + void setInactivityTimeout(InactivityTimeout inactivityTimeout); + + void setAnimationPending(bool animationPending); + nsecs_t getAnimationTime(); + + void clearSpotsByDisplay(int32_t displayId); + + void setHandlerController(std::shared_ptr<PointerController> controller); + void setCallbackController(std::shared_ptr<PointerController> controller); + + sp<PointerControllerPolicyInterface> getPolicy(); + sp<SpriteController> getSpriteController(); + + void initializeDisplayEventReceiver(); + void handleDisplayEvents(); + + class MessageHandler : public virtual android::MessageHandler { + public: + enum { + MSG_INACTIVITY_TIMEOUT, + }; + + void handleMessage(const Message& message) override; + std::weak_ptr<PointerController> pointerController; + }; + + class LooperCallback : public virtual android::LooperCallback { + public: + int handleEvent(int fd, int events, void* data) override; + std::weak_ptr<PointerController> pointerController; + }; + +private: + sp<PointerControllerPolicyInterface> mPolicy; + sp<Looper> mLooper; + sp<SpriteController> mSpriteController; + sp<MessageHandler> mHandler; + sp<LooperCallback> mCallback; + + DisplayEventReceiver mDisplayEventReceiver; + + PointerController& mController; + + mutable std::mutex mLock; + + struct Locked { + bool animationPending; + nsecs_t animationTime; + + InactivityTimeout inactivityTimeout; + } mLocked GUARDED_BY(mLock); + + void resetInactivityTimeoutLocked(); +}; + +} // namespace android + +#endif // _UI_POINTER_CONTROLLER_CONTEXT_H diff --git a/libs/input/TouchSpotController.cpp b/libs/input/TouchSpotController.cpp new file mode 100644 index 000000000000..c7430ceead41 --- /dev/null +++ b/libs/input/TouchSpotController.cpp @@ -0,0 +1,236 @@ +/* + * 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. + */ + +#define LOG_TAG "TouchSpotController" + +// Log debug messages about pointer updates +#define DEBUG_SPOT_UPDATES 0 + +#include "TouchSpotController.h" + +#include <log/log.h> + +#include <SkBitmap.h> +#include <SkBlendMode.h> +#include <SkCanvas.h> +#include <SkColor.h> +#include <SkPaint.h> + +namespace { +// Time to spend fading out the spot completely. +const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms +} // namespace + +namespace android { + +// --- Spot --- + +void TouchSpotController::Spot::updateSprite(const SpriteIcon* icon, float x, float y, + int32_t displayId) { + sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); + sprite->setAlpha(alpha); + sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); + sprite->setPosition(x, y); + sprite->setDisplayId(displayId); + this->x = x; + this->y = y; + + if (icon != mLastIcon) { + mLastIcon = icon; + if (icon) { + sprite->setIcon(*icon); + sprite->setVisible(true); + } else { + sprite->setVisible(false); + } + } +} + +// --- TouchSpotController --- + +TouchSpotController::TouchSpotController(int32_t displayId, PointerControllerContext& context) + : mDisplayId(displayId), mContext(context) { + mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId); +} + +TouchSpotController::~TouchSpotController() { + std::scoped_lock lock(mLock); + + size_t numSpots = mLocked.displaySpots.size(); + for (size_t i = 0; i < numSpots; i++) { + delete mLocked.displaySpots[i]; + } + mLocked.displaySpots.clear(); +} + +void TouchSpotController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits) { +#if DEBUG_SPOT_UPDATES + ALOGD("setSpots: idBits=%08x", spotIdBits.value); + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.firstMarkedBit(); + idBits.clearBit(id); + const PointerCoords& c = spotCoords[spotIdToIndex[id]]; + ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f, displayId=%" PRId32 ".", id, + c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y), + c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), displayId); + } +#endif + + std::scoped_lock lock(mLock); + sp<SpriteController> spriteController = mContext.getSpriteController(); + spriteController->openTransaction(); + + // Add or move spots for fingers that are down. + for (BitSet32 idBits(spotIdBits); !idBits.isEmpty();) { + uint32_t id = idBits.clearFirstMarkedBit(); + const PointerCoords& c = spotCoords[spotIdToIndex[id]]; + const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 + ? mResources.spotTouch + : mResources.spotHover; + float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); + float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); + + Spot* spot = getSpot(id, mLocked.displaySpots); + if (!spot) { + spot = createAndAddSpotLocked(id, mLocked.displaySpots); + } + + spot->updateSprite(&icon, x, y, mDisplayId); + } + + for (Spot* spot : mLocked.displaySpots) { + if (spot->id != Spot::INVALID_ID && !spotIdBits.hasBit(spot->id)) { + fadeOutAndReleaseSpotLocked(spot); + } + } + + spriteController->closeTransaction(); +} + +void TouchSpotController::clearSpots() { +#if DEBUG_SPOT_UPDATES + ALOGD("clearSpots"); +#endif + + std::scoped_lock lock(mLock); + fadeOutAndReleaseAllSpotsLocked(); +} + +TouchSpotController::Spot* TouchSpotController::getSpot(uint32_t id, + const std::vector<Spot*>& spots) { + for (size_t i = 0; i < spots.size(); i++) { + Spot* spot = spots[i]; + if (spot->id == id) { + return spot; + } + } + return nullptr; +} + +TouchSpotController::Spot* TouchSpotController::createAndAddSpotLocked(uint32_t id, + std::vector<Spot*>& spots) { + // Remove spots until we have fewer than MAX_SPOTS remaining. + while (spots.size() >= MAX_SPOTS) { + Spot* spot = removeFirstFadingSpotLocked(spots); + if (!spot) { + spot = spots[0]; + spots.erase(spots.begin()); + } + releaseSpotLocked(spot); + } + + // Obtain a sprite from the recycled pool. + sp<Sprite> sprite; + if (!mLocked.recycledSprites.empty()) { + sprite = mLocked.recycledSprites.back(); + mLocked.recycledSprites.pop_back(); + } else { + sprite = mContext.getSpriteController()->createSprite(); + } + + // Return the new spot. + Spot* spot = new Spot(id, sprite); + spots.push_back(spot); + return spot; +} + +TouchSpotController::Spot* TouchSpotController::removeFirstFadingSpotLocked( + std::vector<Spot*>& spots) REQUIRES(mLock) { + for (size_t i = 0; i < spots.size(); i++) { + Spot* spot = spots[i]; + if (spot->id == Spot::INVALID_ID) { + spots.erase(spots.begin() + i); + return spot; + } + } + return NULL; +} + +void TouchSpotController::releaseSpotLocked(Spot* spot) REQUIRES(mLock) { + spot->sprite->clearIcon(); + + if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { + mLocked.recycledSprites.push_back(spot->sprite); + } + + delete spot; +} + +void TouchSpotController::fadeOutAndReleaseSpotLocked(Spot* spot) REQUIRES(mLock) { + if (spot->id != Spot::INVALID_ID) { + spot->id = Spot::INVALID_ID; + mContext.startAnimation(); + } +} + +void TouchSpotController::fadeOutAndReleaseAllSpotsLocked() REQUIRES(mLock) { + size_t numSpots = mLocked.displaySpots.size(); + for (size_t i = 0; i < numSpots; i++) { + Spot* spot = mLocked.displaySpots[i]; + fadeOutAndReleaseSpotLocked(spot); + } +} + +void TouchSpotController::reloadSpotResources() { + mContext.getPolicy()->loadPointerResources(&mResources, mDisplayId); +} + +bool TouchSpotController::doFadingAnimation(nsecs_t timestamp, bool keepAnimating) { + std::scoped_lock lock(mLock); + nsecs_t animationTime = mContext.getAnimationTime(); + nsecs_t frameDelay = timestamp - animationTime; + size_t numSpots = mLocked.displaySpots.size(); + for (size_t i = 0; i < numSpots;) { + Spot* spot = mLocked.displaySpots[i]; + if (spot->id == Spot::INVALID_ID) { + spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; + if (spot->alpha <= 0) { + mLocked.displaySpots.erase(mLocked.displaySpots.begin() + i); + releaseSpotLocked(spot); + numSpots--; + continue; + } else { + spot->sprite->setAlpha(spot->alpha); + keepAnimating = true; + } + } + ++i; + } + return keepAnimating; +} + +} // namespace android diff --git a/libs/input/TouchSpotController.h b/libs/input/TouchSpotController.h new file mode 100644 index 000000000000..f3b355010bee --- /dev/null +++ b/libs/input/TouchSpotController.h @@ -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. + */ + +#ifndef _UI_TOUCH_SPOT_CONTROLLER_H +#define _UI_TOUCH_SPOT_CONTROLLER_H + +#include "PointerControllerContext.h" + +namespace android { + +/* + * Helper class for PointerController that specifically handles + * touch spot resources and actions for a single display. + */ +class TouchSpotController { +public: + TouchSpotController(int32_t displayId, PointerControllerContext& context); + ~TouchSpotController(); + void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, + BitSet32 spotIdBits); + void clearSpots(); + + void reloadSpotResources(); + bool doFadingAnimation(nsecs_t timestamp, bool keepAnimating); + +private: + struct Spot { + static const uint32_t INVALID_ID = 0xffffffff; + + uint32_t id; + sp<Sprite> sprite; + float alpha; + float scale; + float x, y; + + inline Spot(uint32_t id, const sp<Sprite>& sprite) + : id(id), + sprite(sprite), + alpha(1.0f), + scale(1.0f), + x(0.0f), + y(0.0f), + mLastIcon(nullptr) {} + + void updateSprite(const SpriteIcon* icon, float x, float y, int32_t displayId); + + private: + const SpriteIcon* mLastIcon; + }; + + int32_t mDisplayId; + + mutable std::mutex mLock; + + PointerResources mResources; + + PointerControllerContext& mContext; + + static constexpr size_t MAX_RECYCLED_SPRITES = 12; + static constexpr size_t MAX_SPOTS = 12; + + struct Locked { + std::vector<Spot*> displaySpots; + std::vector<sp<Sprite>> recycledSprites; + + } mLocked GUARDED_BY(mLock); + + Spot* getSpot(uint32_t id, const std::vector<Spot*>& spots); + Spot* createAndAddSpotLocked(uint32_t id, std::vector<Spot*>& spots); + Spot* removeFirstFadingSpotLocked(std::vector<Spot*>& spots); + void releaseSpotLocked(Spot* spot); + void fadeOutAndReleaseSpotLocked(Spot* spot); + void fadeOutAndReleaseAllSpotsLocked(); +}; + +} // namespace android + +#endif // _UI_TOUCH_SPOT_CONTROLLER_H diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index 6e129a064385..b67088a389b6 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -178,9 +178,6 @@ void PointerControllerTest::ensureDisplayViewportIsSet() { viewport.deviceWidth = 400; viewport.deviceHeight = 300; mPointerController->setDisplayViewport(viewport); - - // The first call to setDisplayViewport should trigger the loading of the necessary resources. - EXPECT_TRUE(mPolicy->allResourcesAreLoaded()); } void PointerControllerTest::loopThread() { @@ -208,6 +205,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { TEST_F(PointerControllerTest, updatePointerIcon) { ensureDisplayViewportIsSet(); + mPointerController->setPresentation(PointerController::Presentation::POINTER); mPointerController->unfade(PointerController::Transition::IMMEDIATE); int32_t type = CURSOR_TYPE_ADDITIONAL; @@ -247,8 +245,6 @@ TEST_F(PointerControllerTest, setCustomPointerIcon) { TEST_F(PointerControllerTest, doesNotGetResourcesBeforeSettingViewport) { mPointerController->setPresentation(PointerController::Presentation::POINTER); - mPointerController->setSpots(nullptr, nullptr, BitSet32(), -1); - mPointerController->clearSpots(); mPointerController->setPosition(1.0f, 1.0f); mPointerController->move(1.0f, 1.0f); mPointerController->unfade(PointerController::Transition::IMMEDIATE); diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 6e3fb1991acc..d4fb1be56890 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -147,6 +147,19 @@ public final class AudioDeviceInfo { // {@link android.media.audiopolicy.AudioMix#ROUTE_FLAG_LOOP_BACK} flag. public static final int TYPE_REMOTE_SUBMIX = 25; + /** + * A device type describing a Bluetooth Low Energy (BLE) audio headset or headphones. + * Headphones are grouped with headsets when the device is a sink: + * the features of headsets and headphones with regard to playback are the same. + */ + public static final int TYPE_BLE_HEADSET = 26; + + /** + * A device type describing a Bluetooth Low Energy (BLE) audio speaker. + */ + public static final int TYPE_BLE_SPEAKER = 27; + + /** @hide */ @IntDef(flag = false, prefix = "TYPE", value = { TYPE_BUILTIN_EARPIECE, @@ -171,7 +184,9 @@ public final class AudioDeviceInfo { TYPE_HEARING_AID, TYPE_BUILTIN_MIC, TYPE_FM_TUNER, - TYPE_TV_TUNER } + TYPE_TV_TUNER, + TYPE_BLE_HEADSET, + TYPE_BLE_SPEAKER} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceType {} @@ -193,7 +208,8 @@ public final class AudioDeviceInfo { TYPE_LINE_ANALOG, TYPE_LINE_DIGITAL, TYPE_IP, - TYPE_BUS } + TYPE_BUS, + TYPE_BLE_HEADSET} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeIn {} @@ -219,7 +235,9 @@ public final class AudioDeviceInfo { TYPE_AUX_LINE, TYPE_IP, TYPE_BUS, - TYPE_HEARING_AID } + TYPE_HEARING_AID, + TYPE_BLE_HEADSET, + TYPE_BLE_SPEAKER} ) @Retention(RetentionPolicy.SOURCE) public @interface AudioDeviceTypeOut {} @@ -248,7 +266,8 @@ public final class AudioDeviceInfo { case TYPE_BUS: case TYPE_HEARING_AID: case TYPE_BUILTIN_SPEAKER_SAFE: - case TYPE_REMOTE_SUBMIX: + case TYPE_BLE_HEADSET: + case TYPE_BLE_SPEAKER: return true; default: return false; @@ -275,6 +294,7 @@ public final class AudioDeviceInfo { case TYPE_IP: case TYPE_BUS: case TYPE_REMOTE_SUBMIX: + case TYPE_BLE_HEADSET: return true; default: return false; @@ -527,6 +547,8 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER_SAFE, TYPE_BUILTIN_SPEAKER_SAFE); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_HEADSET, TYPE_BLE_HEADSET); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLE_SPEAKER, TYPE_BLE_SPEAKER); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO); @@ -547,6 +569,7 @@ public final class AudioDeviceInfo { INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_IP, TYPE_IP); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUS, TYPE_BUS); INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, TYPE_REMOTE_SUBMIX); + INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLE_HEADSET, TYPE_BLE_HEADSET); // privileges mapping to output device EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray(); @@ -576,6 +599,8 @@ public final class AudioDeviceInfo { EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER_SAFE, AudioSystem.DEVICE_OUT_SPEAKER_SAFE); EXT_TO_INT_DEVICE_MAPPING.put(TYPE_REMOTE_SUBMIX, AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET); + EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLE_SPEAKER, AudioSystem.DEVICE_OUT_BLE_SPEAKER); } } diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index 42d0f0cc13c5..f6b04540c5c7 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -70,7 +70,9 @@ public class AudioDevicePort extends AudioPort { * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number * and device number: "card=2;device=1" * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, - * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}) + * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, + * {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP}), + * {@link AudioManager#DEVICE_OUT_BLE_HEADSET}, {@link AudioManager#DEVICE_OUT_BLE_SPEAKER}) * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by * {@link BluetoothDevice#getAddress()}. * - Deivces that do not have an address will indicate an empty string "". diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 408f34be6b65..b2e0538fd4b8 100755 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -4413,6 +4413,18 @@ public class AudioManager { */ public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; /** @hide + * The audio output device code for echo reference injection point. + */ + public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; + /** @hide + * The audio output device code for a BLE audio headset. + */ + public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; + /** @hide + * The audio output device code for a BLE audio speaker. + */ + public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; + /** @hide * This is not used as a returned value from {@link #getDevicesForStream}, but could be * used in the future in a set method to select whatever default device is chosen by the * platform-specific implementation. @@ -4496,6 +4508,14 @@ public class AudioManager { * The audio input device code for audio loopback */ public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; + /** @hide + * The audio input device code for an echo reference capture point. + */ + public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; + /** @hide + * The audio input device code for a BLE audio headset. + */ + public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; /** * Return true if the device code corresponds to an output device. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index da52cfef6bc6..5fe5c0580b0c 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -866,6 +866,12 @@ public class AudioSystem public static final int DEVICE_OUT_USB_HEADSET = 0x4000000; /** @hide */ public static final int DEVICE_OUT_HEARING_AID = 0x8000000; + /** @hide */ + public static final int DEVICE_OUT_ECHO_CANCELLER = 0x10000000; + /** @hide */ + public static final int DEVICE_OUT_BLE_HEADSET = 0x20000000; + /** @hide */ + public static final int DEVICE_OUT_BLE_SPEAKER = 0x20000001; /** @hide */ public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; @@ -890,6 +896,8 @@ public class AudioSystem public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET; /** @hide */ public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET; + /** @hide */ + public static final Set<Integer> DEVICE_OUT_ALL_BLE_SET; static { DEVICE_OUT_ALL_SET = new HashSet<>(); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE); @@ -920,6 +928,9 @@ public class AudioSystem DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ECHO_CANCELLER); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLE_SPEAKER); DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT); DEVICE_OUT_ALL_A2DP_SET = new HashSet<>(); @@ -945,6 +956,10 @@ public class AudioSystem DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>(); DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET); DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER); + + DEVICE_OUT_ALL_BLE_SET = new HashSet<>(); + DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_HEADSET); + DEVICE_OUT_ALL_BLE_SET.add(DEVICE_OUT_BLE_SPEAKER); } // input devices @@ -1019,6 +1034,8 @@ public class AudioSystem /** @hide */ public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000; /** @hide */ + public static final int DEVICE_IN_BLE_HEADSET = DEVICE_BIT_IN | 0x20000000; + /** @hide */ @UnsupportedAppUsage public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; @@ -1056,6 +1073,7 @@ public class AudioSystem DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE); DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC); DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BLE_HEADSET); DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT); DEVICE_IN_ALL_SCO_SET = new HashSet<>(); @@ -1118,6 +1136,9 @@ public class AudioSystem /** @hide */ public static final String DEVICE_OUT_PROXY_NAME = "proxy"; /** @hide */ public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset"; /** @hide */ public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out"; + /** @hide */ public static final String DEVICE_OUT_ECHO_CANCELLER_NAME = "echo_canceller"; + /** @hide */ public static final String DEVICE_OUT_BLE_HEADSET_NAME = "ble_headset"; + /** @hide */ public static final String DEVICE_OUT_BLE_SPEAKER_NAME = "ble_speaker"; /** @hide */ public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; /** @hide */ public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; @@ -1145,6 +1166,7 @@ public class AudioSystem /** @hide */ public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble"; /** @hide */ public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference"; /** @hide */ public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc"; + /** @hide */ public static final String DEVICE_IN_BLE_HEADSET_NAME = "ble_headset"; /** @hide */ @UnsupportedAppUsage @@ -1207,6 +1229,12 @@ public class AudioSystem return DEVICE_OUT_USB_HEADSET_NAME; case DEVICE_OUT_HEARING_AID: return DEVICE_OUT_HEARING_AID_NAME; + case DEVICE_OUT_ECHO_CANCELLER: + return DEVICE_OUT_ECHO_CANCELLER_NAME; + case DEVICE_OUT_BLE_HEADSET: + return DEVICE_OUT_BLE_HEADSET_NAME; + case DEVICE_OUT_BLE_SPEAKER: + return DEVICE_OUT_BLE_SPEAKER_NAME; case DEVICE_OUT_DEFAULT: default: return Integer.toString(device); @@ -1269,6 +1297,8 @@ public class AudioSystem return DEVICE_IN_ECHO_REFERENCE_NAME; case DEVICE_IN_HDMI_ARC: return DEVICE_IN_HDMI_ARC_NAME; + case DEVICE_IN_BLE_HEADSET: + return DEVICE_IN_BLE_HEADSET_NAME; case DEVICE_IN_DEFAULT: default: return Integer.toString(device); diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java index e959e8e36b42..5d4404036102 100644 --- a/media/java/android/media/MediaTranscodeManager.java +++ b/media/java/android/media/MediaTranscodeManager.java @@ -225,13 +225,35 @@ public final class MediaTranscodeManager { job.updateStatusAndResult(TranscodingJob.STATUS_FINISHED, TranscodingJob.RESULT_ERROR); - // Notifies client the job is done. + // Notifies client the job failed. if (job.mListener != null && job.mListenerExecutor != null) { job.mListenerExecutor.execute(() -> job.mListener.onTranscodingFinished(job)); } } } + private void handleTranscodingProgressUpdate(int jobId, int newProgress) { + synchronized (mPendingTranscodingJobs) { + // Gets the job associated with the jobId. + final TranscodingJob job = mPendingTranscodingJobs.get(jobId); + + if (job == null) { + // This should not happen in reality. + Log.e(TAG, "Job " + jobId + " is not in PendingJobs"); + return; + } + + // Updates the job progress. + job.setJobProgress(newProgress); + + // Notifies client the progress update. + if (job.mProgressUpdateExecutor != null && job.mProgressUpdateListener != null) { + job.mProgressUpdateExecutor.execute( + () -> job.mProgressUpdateListener.onProgressUpdate(newProgress)); + } + } + } + // Just forwards all the events to the event handler. private ITranscodingClientCallback mTranscodingClientCallback = new ITranscodingClientCallback.Stub() { @@ -294,8 +316,8 @@ public final class MediaTranscodeManager { } @Override - public void onProgressUpdate(int jobId, int progress) throws RemoteException { - //TODO(hkuang): Implement this. + public void onProgressUpdate(int jobId, int newProgress) throws RemoteException { + handleTranscodingProgressUpdate(jobId, newProgress); } }; @@ -821,17 +843,8 @@ public final class MediaTranscodeManager { return mResult; } - private void setJobProgress(int newProgress) { - synchronized (this) { - mProgress = newProgress; - } - - // Notify listener. - OnProgressUpdateListener onProgressUpdateListener = mProgressUpdateListener; - if (mProgressUpdateListener != null) { - mProgressUpdateExecutor.execute( - () -> onProgressUpdateListener.onProgressUpdate(mProgress)); - } + private synchronized void setJobProgress(int newProgress) { + mProgress = newProgress; } } diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java index 561a8847feed..697d80c6b78e 100644 --- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java +++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java @@ -220,6 +220,34 @@ public class AudioPolicyConfig implements Parcelable { return textDump; } + /** + * Very short dump of configuration + * @return a condensed dump of configuration, uniquely identifies a policy in a log + */ + public String toCompactLogString() { + String compactDump = "reg:" + mRegistrationId; + int mixNum = 0; + for (AudioMix mix : mMixes) { + compactDump += " Mix:" + mixNum + "-Typ:" + mixTypePrefix(mix.getMixType()) + + "-Rul:" + mix.getRule().getCriteria().size(); + mixNum++; + } + return compactDump; + } + + private static String mixTypePrefix(int mixType) { + switch (mixType) { + case AudioMix.MIX_TYPE_PLAYERS: + return "p"; + case AudioMix.MIX_TYPE_RECORDERS: + return "r"; + case AudioMix.MIX_TYPE_INVALID: + default: + return "#"; + + } + } + protected void reset() { mMixCounter = 0; } diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java index 3a5e69293a02..8e4153078174 100644 --- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java +++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java @@ -37,6 +37,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; /* * Functional tests for MediaTranscodeManager in the media framework. @@ -230,5 +231,63 @@ public class MediaTranscodeManagerTest 30, TimeUnit.MILLISECONDS); assertTrue("Fails to cancel transcoding", finishedOnTime); } + + + @Test + public void testTranscodingProgressUpdate() throws Exception { + Log.d(TAG, "Starting: testMediaTranscodeManager"); + + Semaphore transcodeCompleteSemaphore = new Semaphore(0); + + // Create a file Uri: file:///data/user/0/com.android.mediatranscodingtest/cache/temp.mp4 + // The full path of this file is: + // /data/user/0/com.android.mediatranscodingtest/cache/temp.mp4 + Uri destinationUri = Uri.parse(ContentResolver.SCHEME_FILE + "://" + + mContext.getCacheDir().getAbsolutePath() + "/HevcTranscode.mp4"); + + TranscodingRequest request = + new TranscodingRequest.Builder() + .setSourceUri(mSourceHEVCVideoUri) + .setDestinationUri(destinationUri) + .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO) + .setPriority(MediaTranscodeManager.PRIORITY_REALTIME) + .setVideoTrackFormat(createMediaFormat()) + .build(); + Executor listenerExecutor = Executors.newSingleThreadExecutor(); + + Log.i(TAG, "transcoding to " + createMediaFormat()); + + TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor, + transcodingJob -> { + Log.d(TAG, "Transcoding completed with result: " + transcodingJob.getResult()); + assertEquals(transcodingJob.getResult(), TranscodingJob.RESULT_SUCCESS); + transcodeCompleteSemaphore.release(); + }); + assertNotNull(job); + + AtomicInteger progressUpdateCount = new AtomicInteger(0); + + // Set progress update executor and use the same executor as result listener. + job.setOnProgressUpdateListener(listenerExecutor, + new TranscodingJob.OnProgressUpdateListener() { + int mPreviousProgress = 0; + + @Override + public void onProgressUpdate(int newProgress) { + assertTrue("Invalid proress update", newProgress > mPreviousProgress); + assertTrue("Invalid proress update", newProgress <= 100); + mPreviousProgress = newProgress; + progressUpdateCount.getAndIncrement(); + Log.i(TAG, "Get progress update " + newProgress); + } + }); + + Log.d(TAG, "testMediaTranscodeManager - Waiting for transcode to cancel."); + boolean finishedOnTime = transcodeCompleteSemaphore.tryAcquire( + TRANSCODE_TIMEOUT_SECONDS, TimeUnit.SECONDS); + assertTrue("Transcode failed to complete in time.", finishedOnTime); + assertTrue("Failed to receive at least 10 progress updates", + progressUpdateCount.get() > 10); + } } diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 70ef69d8ce72..e06cf945ddaa 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -24047,6 +24047,8 @@ package android.media { method public boolean isSink(); method public boolean isSource(); field public static final int TYPE_AUX_LINE = 19; // 0x13 + field public static final int TYPE_BLE_HEADSET = 26; // 0x1a + field public static final int TYPE_BLE_SPEAKER = 27; // 0x1b field public static final int TYPE_BLUETOOTH_A2DP = 8; // 0x8 field public static final int TYPE_BLUETOOTH_SCO = 7; // 0x7 field public static final int TYPE_BUILTIN_EARPIECE = 1; // 0x1 diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt index 86ac3e477dc4..35b483b9fb84 100644 --- a/non-updatable-api/module-lib-current.txt +++ b/non-updatable-api/module-lib-current.txt @@ -54,6 +54,7 @@ package android.os { } public interface Parcelable { + method public default int getStability(); field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0 field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1 } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 10887fabb5c7..0906a060c40f 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -9357,7 +9357,7 @@ package android.telecom { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle); method @Deprecated public android.content.ComponentName getDefaultPhoneApp(); - method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); + method @Deprecated public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); diff --git a/packages/CarSystemUI/samples/sample1/rro/Android.bp b/packages/CarSystemUI/samples/sample1/rro/Android.bp new file mode 100644 index 000000000000..5b0347ff73fd --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/Android.bp @@ -0,0 +1,27 @@ +// +// 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. +// + +android_app { + name: "CarSystemUISampleOneRRO", + resource_dirs: ["res"], + certificate: "platform", + platform_apis: true, + manifest: "AndroidManifest.xml", + aaptflags: [ + "--no-resource-deduping", + "--no-resource-removal", + ] +}
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml b/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml new file mode 100644 index 000000000000..5c25056f7915 --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/AndroidManifest.xml @@ -0,0 +1,24 @@ +<!-- + ~ 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.systemui.rro"> + <overlay + android:targetPackage="com.android.systemui" + android:isStatic="false" + android:resourcesMap="@xml/car_sysui_overlays" + /> +</manifest>
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml b/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml new file mode 100644 index 000000000000..854ab7d7e49b --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/res/values/config.xml @@ -0,0 +1,47 @@ +<?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. + --> + +<resources> + <!-- Configure which system bars should be displayed. --> + <bool name="config_enableTopNavigationBar">true</bool> + <bool name="config_enableLeftNavigationBar">true</bool> + <bool name="config_enableRightNavigationBar">true</bool> + <bool name="config_enableBottomNavigationBar">true</bool> + + <!-- Configure the type of each system bar. Each system bar must have a unique type. --> + <!-- STATUS_BAR = 0--> + <!-- NAVIGATION_BAR = 1--> + <!-- STATUS_BAR_EXTRA = 2--> + <!-- NAVIGATION_BAR_EXTRA = 3--> + <integer name="config_topSystemBarType">0</integer> + <integer name="config_leftSystemBarType">2</integer> + <integer name="config_rightSystemBarType">3</integer> + <integer name="config_bottomSystemBarType">1</integer> + + <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g. + if both top bar and left bar are enabled, it creates an overlapping space in the upper left + corner), the system bar with the higher z-order takes the overlapping space and padding is + applied to the other bar.--> + <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a + RuntimeException, since their placing order cannot be determined. Bars that do not overlap + are allowed to have the same z-order. --> + <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. --> + <integer name="config_topSystemBarZOrder">1</integer> + <integer name="config_leftSystemBarZOrder">0</integer> + <integer name="config_rightSystemBarZOrder">0</integer> + <integer name="config_bottomSystemBarZOrder">10</integer> +</resources>
\ No newline at end of file diff --git a/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml new file mode 100644 index 000000000000..7bcb8e1b43dd --- /dev/null +++ b/packages/CarSystemUI/samples/sample1/rro/res/xml/car_sysui_overlays.xml @@ -0,0 +1,33 @@ + +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<overlay> + <item target="bool/config_enableTopNavigationBar" value="@bool/config_enableTopNavigationBar"/> + <item target="bool/config_enableLeftNavigationBar" value="@bool/config_enableLeftNavigationBar"/> + <item target="bool/config_enableRightNavigationBar" value="@bool/config_enableRightNavigationBar"/> + <item target="bool/config_enableBottomNavigationBar" value="@bool/config_enableBottomNavigationBar"/> + + <item target="integer/config_topSystemBarType" value="@integer/config_topSystemBarType"/> + <item target="integer/config_leftSystemBarType" value="@integer/config_leftSystemBarType"/> + <item target="integer/config_rightSystemBarType" value="@integer/config_rightSystemBarType"/> + <item target="integer/config_bottomSystemBarType" value="@integer/config_bottomSystemBarType"/> + + <item target="integer/config_topSystemBarZOrder" value="@integer/config_topSystemBarZOrder"/> + <item target="integer/config_leftSystemBarZOrder" value="@integer/config_leftSystemBarZOrder"/> + <item target="integer/config_rightSystemBarZOrder" value="@integer/config_rightSystemBarZOrder"/> + <item target="integer/config_bottomSystemBarZOrder" value="@integer/config_bottomSystemBarZOrder"/> +</overlay>
\ No newline at end of file diff --git a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java index 8efbad64f3d2..2c4545e7b265 100644 --- a/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java +++ b/packages/FusedLocation/test/src/com/android/location/fused/tests/FusedLocationServiceTest.java @@ -155,41 +155,6 @@ public class FusedLocationServiceTest { assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location); } - @Test - public void testBypassRequest() throws Exception { - LocationRequest request = LocationRequest.createFromDeprecatedProvider(FUSED_PROVIDER, 1000, - 0, false).setQuality(LocationRequest.POWER_HIGH).setLocationSettingsIgnored(true); - - mProvider.setRequest( - new ProviderRequest.Builder() - .setInterval(1000) - .setLocationSettingsIgnored(true) - .setLocationRequests(Collections.singletonList(request)) - .build(), - new WorkSource()); - - boolean containsNetworkBypass = false; - for (LocationRequest iRequest : mLocationManager.getTestProviderCurrentRequests( - NETWORK_PROVIDER)) { - if (iRequest.isLocationSettingsIgnored()) { - containsNetworkBypass = true; - break; - } - } - - boolean containsGpsBypass = false; - for (LocationRequest iRequest : mLocationManager.getTestProviderCurrentRequests( - GPS_PROVIDER)) { - if (iRequest.isLocationSettingsIgnored()) { - containsGpsBypass = true; - break; - } - } - - assertThat(containsNetworkBypass).isTrue(); - assertThat(containsGpsBypass).isTrue(); - } - private static class LocationProviderManagerCapture extends ILocationProviderManager.Stub { private final LinkedBlockingQueue<Location> mLocations; 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/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index ddf2bc0991a4..5f5be97c322c 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -165,7 +165,7 @@ <string name="tts_lang_not_selected" msgid="7927823081096056147">"Langue non sélectionnée"</string> <string name="tts_default_lang_summary" msgid="9042620014800063470">"Définir la langue utilisée par la synthèse vocale"</string> <string name="tts_play_example_title" msgid="1599468547216481684">"Écouter un échantillon"</string> - <string name="tts_play_example_summary" msgid="634044730710636383">"Lire une courte démonstration de la synthèse vocale"</string> + <string name="tts_play_example_summary" msgid="634044730710636383">"Écoutez une courte démonstration de la synthèse vocale"</string> <string name="tts_install_data_title" msgid="1829942496472751703">"Installer les données vocales"</string> <string name="tts_install_data_summary" msgid="3608874324992243851">"Installer les données nécessaires à la synthèse vocale"</string> <string name="tts_engine_security_warning" msgid="3372432853837988146">"Ce moteur de synthèse vocale est susceptible de collecter tout ce qui sera lu, y compris les données personnelles comme les mots de passe et les numéros de carte de paiement. Il provient du moteur <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Voulez-vous activer son utilisation ?"</string> @@ -189,8 +189,8 @@ <item msgid="1158955023692670059">"Rapide"</item> <item msgid="5664310435707146591">"Plus rapide"</item> <item msgid="5491266922147715962">"Très rapide"</item> - <item msgid="7659240015901486196">"Rapide"</item> - <item msgid="7147051179282410945">"Très rapide"</item> + <item msgid="7659240015901486196">"Beaucoup plus rapide"</item> + <item msgid="7147051179282410945">"Extrêmement rapide"</item> <item msgid="581904787661470707">"La plus rapide"</item> </string-array> <string name="choose_profile" msgid="343803890897657450">"Sélectionner un profil"</string> 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/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java index 8e0161961a49..85f25528f07e 100644 --- a/packages/Shell/src/com/android/shell/Screenshooter.java +++ b/packages/Shell/src/com/android/shell/Screenshooter.java @@ -17,11 +17,8 @@ package com.android.shell; import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Rect; -import android.hardware.display.DisplayManagerGlobal; +import android.os.IBinder; import android.util.Log; -import android.view.Display; import android.view.SurfaceControl; /** @@ -40,22 +37,17 @@ final class Screenshooter { * @return The screenshot bitmap on success, null otherwise. */ static Bitmap takeScreenshot() { - Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(Display.DEFAULT_DISPLAY); - Point displaySize = new Point(); - display.getRealSize(displaySize); - final int displayWidth = displaySize.x; - final int displayHeight = displaySize.y; - - int rotation = display.getRotation(); - Rect crop = new Rect(0, 0, displayWidth, displayHeight); - Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight); + Log.d(TAG, "Taking fullscreen screenshot"); // Take the screenshot - Bitmap screenShot = - SurfaceControl.screenshot(crop, displayWidth, displayHeight, rotation); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap screenShot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); if (screenShot == null) { - Log.e(TAG, "Failed to take screenshot of dimensions " + displayWidth + " x " - + displayHeight); + Log.e(TAG, "Failed to take fullscreen screenshot"); return null; } diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index 53eb2343d26a..401f3e3e0685 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -27,6 +27,7 @@ <item name="android:textColor">?attr/wallpaperTextColorSecondary</item> <item name="android:textSize">14dp</item> <item name="android:background">@drawable/kg_emergency_button_background</item> + <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item> <item name="android:paddingLeft">12dp</item> <item name="android:paddingRight">12dp</item> </style> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media.xml b/packages/SystemUI/res/drawable-television/ic_volume_media.xml new file mode 100644 index 000000000000..e43c4b471db4 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media.xml @@ -0,0 +1,26 @@ +<?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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z"/> +</vector> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml new file mode 100644 index 000000000000..0f6dc9517f53 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media_low.xml @@ -0,0 +1,26 @@ +<?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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M3,15V9H7L12,4V20L7,15H3ZM14,7.97C15.48,8.71 16.5,10.23 16.5,12C16.5,13.77 15.48,15.29 14,16.02V7.97Z"/> +</vector> diff --git a/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml new file mode 100644 index 000000000000..4b59e13516d2 --- /dev/null +++ b/packages/SystemUI/res/drawable-television/ic_volume_media_mute.xml @@ -0,0 +1,27 @@ +<?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 + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="@color/tv_volume_dialog_accent" + android:pathData="M16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v2.21l2.45,2.45c0.03,-0.2 0.05,-0.41 0.05,-0.63zM19,12c0,0.94 -0.2,1.82 -0.54,2.64l1.51,1.51C20.63,14.91 21,13.5 21,12c0,-4.28 -2.99,-7.86 -7,-8.77v2.06c2.89,0.86 5,3.54 5,6.71zM4.27,3L3,4.27 7.73,9L3,9v6h4l5,5v-6.73l4.25,4.25c-0.67,0.52 -1.42,0.93 -2.25,1.18v2.06c1.38,-0.31 2.63,-0.95 3.69,-1.81L19.73,21 21,19.73l-9,-9L4.27,3zM12,4L9.91,6.09 12,8.18L12,4z"/> +</vector> + diff --git a/packages/SystemUI/res/drawable/ic_volume_media_low.xml b/packages/SystemUI/res/drawable/ic_volume_media_low.xml new file mode 100644 index 000000000000..87591de39d54 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_volume_media_low.xml @@ -0,0 +1,18 @@ +<!-- + 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. +--> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:drawable="@drawable/ic_volume_media" /> +</selector> diff --git a/packages/SystemUI/res/drawable/tv_ring_white.xml b/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml index 0f7cc1082f71..93f8724b22a9 100644 --- a/packages/SystemUI/res/drawable/tv_ring_white.xml +++ b/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml @@ -16,10 +16,10 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> + android:shape="rectangle"> - <stroke - android:width="1dp" - android:color="@android:color/white" /> + <corners android:radius="20dp"/> + <solid android:color="@color/tv_audio_recording_indicator_icon_background"/> + <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/> </shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/tv_circle_dark.xml b/packages/SystemUI/res/drawable/tv_volume_dialog_background.xml index d1ba8e71ec31..fee6e57d2e86 100644 --- a/packages/SystemUI/res/drawable/tv_circle_dark.xml +++ b/packages/SystemUI/res/drawable/tv_volume_dialog_background.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2019 The Android Open Source Project + ~ 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. @@ -16,9 +16,9 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> + android:shape="rectangle"> - <solid - android:color="@color/tv_audio_recording_indicator_background" /> + <solid android:color="@color/tv_volume_dialog_background" /> + <corners android:radius="@dimen/tv_volume_dialog_corner_radius"/> -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml b/packages/SystemUI/res/drawable/tv_volume_dialog_circle.xml index 55d21de00ca3..3c4fc05914f8 100644 --- a/packages/SystemUI/res/drawable/tv_circle_white_translucent.xml +++ b/packages/SystemUI/res/drawable/tv_volume_dialog_circle.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2019 The Android Open Source Project + ~ 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. @@ -17,8 +17,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> + <solid android:color="@color/tv_volume_dialog_circle" /> - <solid - android:color="@color/tv_audio_recording_indicator_pulse" /> - -</shape>
\ No newline at end of file +</shape> diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog.xml b/packages/SystemUI/res/layout-land-television/volume_dialog.xml index e0d158d757b3..56d847c6aa2e 100644 --- a/packages/SystemUI/res/layout-land-television/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land-television/volume_dialog.xml @@ -20,7 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <FrameLayout android:id="@+id/volume_dialog" @@ -46,7 +46,7 @@ android:translationZ="@dimen/volume_dialog_elevation" android:clipChildren="false" android:clipToPadding="false" - android:background="@drawable/rounded_bg_full"> + android:background="@drawable/tv_volume_dialog_background"> <LinearLayout android:id="@+id/volume_dialog_rows" @@ -54,9 +54,7 @@ android:layout_height="wrap_content" android:minWidth="@dimen/volume_dialog_panel_width" android:gravity="center" - android:orientation="horizontal" - android:paddingRight="@dimen/volume_dialog_stream_padding" - android:paddingLeft="@dimen/volume_dialog_stream_padding"> + android:orientation="horizontal"> <!-- volume rows added and removed here! :-) --> </LinearLayout> @@ -98,4 +96,4 @@ </FrameLayout> -</FrameLayout>
\ No newline at end of file +</FrameLayout> diff --git a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml index 08209ab09169..c0f0aa8bbc8d 100644 --- a/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout-land-television/volume_dialog_row.xml @@ -21,11 +21,12 @@ android:background="@android:color/transparent" android:clipChildren="false" android:clipToPadding="false" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" + android:padding="@dimen/tv_volume_dialog_row_padding" android:background="@android:color/transparent" android:gravity="center" android:layout_gravity="center" @@ -33,9 +34,9 @@ <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/volume_row_icon" style="@style/VolumeButtons" - android:layout_width="@dimen/volume_dialog_tap_target_size" - android:layout_height="@dimen/volume_dialog_tap_target_size" - android:background="@drawable/ripple_drawable_20dp" + android:layout_width="@dimen/tv_volume_dialog_bubble_size" + android:layout_height="@dimen/tv_volume_dialog_bubble_size" + android:background="@drawable/tv_volume_dialog_circle" android:tint="@color/accent_tint_color_selector" android:soundEffectsEnabled="false" /> <TextView @@ -62,6 +63,15 @@ android:layout_gravity="center" android:rotation="0" /> </FrameLayout> + <TextView + android:id="@+id/volume_number" + android:layout_width="@dimen/tv_volume_dialog_bubble_size" + android:layout_height="@dimen/tv_volume_dialog_bubble_size" + android:maxLength="2" + android:gravity="center" + android:background="@drawable/tv_volume_dialog_circle" + android:textSize="@dimen/tv_volume_number_text_size" + android:textColor="@color/accent_tint_color_selector"/> </LinearLayout> <include layout="@layout/volume_dnd_icon"/> diff --git a/packages/SystemUI/res/layout-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml index 5da7819c3d76..c420117073c5 100644 --- a/packages/SystemUI/res/layout-land/volume_dialog.xml +++ b/packages/SystemUI/res/layout-land/volume_dialog.xml @@ -22,7 +22,7 @@ android:gravity="right" android:layout_gravity="right" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <FrameLayout android:id="@+id/volume_dialog" diff --git a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml index 1d2340dadb8a..f9336a540376 100644 --- a/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml +++ b/packages/SystemUI/res/layout/tv_audio_recording_indicator.xml @@ -19,7 +19,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - android:padding="32dp"> + android:padding="12dp"> <FrameLayout android:layout_width="wrap_content" @@ -32,45 +32,25 @@ android:orientation="horizontal"> <FrameLayout - android:layout_width="45dp" - android:layout_height="47dp"> + android:layout_width="wrap_content" + android:layout_height="match_parent"> <View android:id="@+id/icon_container_bg" - android:layout_width="match_parent" + android:layout_width="50dp" android:layout_height="match_parent" android:background="@drawable/tv_rect_dark_left_rounded"/> <FrameLayout android:id="@+id/icon_mic" - android:layout_width="35dp" - android:layout_height="35dp" - android:layout_marginStart="6dp" - android:layout_marginTop="6dp" - android:layout_marginBottom="6dp"> - - <View - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:background="@drawable/tv_circle_dark"/> - - <ImageView - android:id="@+id/pulsating_circle" - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:background="@drawable/tv_circle_white_translucent"/> - - <ImageView - android:layout_width="27dp" - android:layout_height="27dp" - android:layout_gravity="center" - android:src="@drawable/tv_ring_white"/> + android:layout_width="34dp" + android:layout_height="24dp" + android:layout_gravity="center" + android:background="@drawable/tv_rect_shadow_rounded"> <ImageView - android:layout_width="16dp" - android:layout_height="16dp" + android:layout_width="13dp" + android:layout_height="13dp" android:layout_gravity="center" android:background="@drawable/tv_ic_mic_white"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index 7d6547b9cd42..a90b1eb471ff 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -22,7 +22,7 @@ android:gravity="right" android:layout_gravity="right" android:background="@android:color/transparent" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <!-- right-aligned to be physically near volume button --> <LinearLayout diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml index 6128da8627a9..b9efc5be70c1 100644 --- a/packages/SystemUI/res/layout/volume_dialog_row.xml +++ b/packages/SystemUI/res/layout/volume_dialog_row.xml @@ -20,7 +20,7 @@ android:layout_width="@dimen/volume_dialog_panel_width" android:clipChildren="false" android:clipToPadding="false" - android:theme="@style/qs_theme"> + android:theme="@style/volume_dialog_theme"> <LinearLayout android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ee8700261db5..bac915d854d8 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Versteek die huidige sessie."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Versteek"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Maak toe"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 03eb39659ef3..aedbded46298 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ሚዲያ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"የአሁኑን ክፍለ-ጊዜ ደብቅ።"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ደብቅ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ቅንብሮች"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 95d54a2386dd..fee86ca42fe6 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1093,7 +1093,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string> <string name="controls_media_title" msgid="1746947284862928133">"الوسائط"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"إخفاء الجلسة الحالية"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"إخفاء"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"الإعدادات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 3023a27b15b4..3778df80197b 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"বৰ্তমানৰ ছেশ্বনটো লুকুৱাওক।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকুৱাওক"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ছেটিংসমূহ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 3c8e04b7ba35..874bf7465827 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Cari sessiyanı gizlədin."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizlədin"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 4b400eb479c9..2a120c57e955 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrijte aktuelnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Podešavanja"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f1064fb7b1d7..e4bb67ae65c6 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультымедыя"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Схаваць цяперашні сеанс."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Схаваць"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налады"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 8ba2a1e51769..c51e58ccd6cf 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мултимедия"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Скриване на текущата сесия."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скриване"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 5861c44c1cbb..3d00ca858ef5 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string> <string name="controls_media_title" msgid="1746947284862928133">"মিডিয়া"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"বর্তমান সেশন লুকান।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"লুকান"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"সেটিংস"</string> <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string> @@ -1084,8 +1085,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> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <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-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 984cbebd42eb..14259840d503 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrijte trenutnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index b8c41efa7813..b1501558f924 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimèdia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Amaga la sessió actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Amaga"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuració"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index f946cc4f9552..ae6cc13cd1df 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skrýt aktuální relaci."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrýt"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavení"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index a6de8a618f23..09f7f1a8762e 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medie"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skjul den aktuelle session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Indstillinger"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 372cc1166fce..2410e4785c8d 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medien"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Du kannst die aktuelle Sitzung ausblenden."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ausblenden"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Einstellungen"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string> @@ -1084,8 +1085,6 @@ <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 /> + <string name="one_handed_tutorial_title" msgid="6312198435090726656">"Einhandmodus verwenden"</string> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Wenn du die App schließen möchtest, wische vom unteren Rand des Displays nach oben oder tippe auf eine beliebige Stelle oberhalb der App"</string> </resources> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index b4673476bad5..f66c5a88b102 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string> <string name="controls_media_title" msgid="1746947284862928133">"Μέσα"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Απόκρυψη της τρέχουσας περιόδου λειτουργίας."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Απόκρυψη"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ρυθμίσεις"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index f73dad3a8bef..acf087d51181 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 7fa7f83c5f12..0e22b583352c 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 6140bf1eea3d..4f4238a5eb45 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Hide the current session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Hide"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dismiss"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Settings"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 6818116ec9b5..45e072496b25 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenido multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculta la sesión actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index f09a0d24b26e..f7ebbd02708a 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar la sesión."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ajustes"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 6236f251f55d..1e5e49e0a143 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string> <string name="controls_media_title" msgid="1746947284862928133">"Meedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Peidetakse praegune seanss."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Peida"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Seaded"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 167a09c71ce3..38b2103d7973 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia-edukia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ezkutatu uneko saioa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ezkutatu"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Baztertu"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ezarpenak"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string> @@ -1085,5 +1085,5 @@ <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> + <string name="one_handed_tutorial_description" msgid="7674850272340517174">"Ateratzeko, pasatu hatza pantailaren behealdetik gora edo sakatu aplikazioaren gainaldea"</string> </resources> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 055505200cc2..d39d0c3d5027 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیهها"</string> <string name="controls_media_title" msgid="1746947284862928133">"رسانه"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"جلسه فعلی پنهان شود."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"پنهان کردن"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"رد کردن"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"تنظیمات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index ec9bbc4a8929..fa076c4fc40e 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Piilota nykyinen käyttökerta."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Piilota"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Asetukset"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 6c5387f63eda..9c418f79a075 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Commandes multimédias"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Masquer la session en cours."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 3a2ae07bc64d..3e2f5fdbff1d 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Masquer la session en cours."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Masquer"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Paramètres"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 25c7b4bfab59..9ecd75e80a4c 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contido multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculta a sesión actual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configuración"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 17cc5a45aeb9..6e05a540a13e 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string> <string name="controls_media_title" msgid="1746947284862928133">"મીડિયા"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"હાલનું સત્ર છુપાવો."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"છુપાવો"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"સેટિંગ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string> @@ -1084,8 +1085,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> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <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-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 97ae7b6e8926..de4fc482a101 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1071,7 +1071,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"इस मीडिया सेशन को छिपाएं."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"छिपाएं"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"खारिज करें"</string> <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग"</string> <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string> @@ -1086,6 +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_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 9e17735ef18d..4bebe79c3c44 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mediji"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sakrij trenutačnu sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sakrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Postavke"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 804587f9bdcd..42e251fb39de 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Média"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Jelenlegi munkamenet elrejtése."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Elrejtés"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Beállítások"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 08ef489901ee..e6b71395c42a 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string> <string name="controls_media_title" msgid="1746947284862928133">"Մեդիա"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Թաքցրեք ընթացիկ աշխատաշրջանը"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Թաքցնել"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Կարգավորումներ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index ba9eca3f0de9..fec4205ba7da 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Menyembunyikan sesi saat ini."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setelan"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 629581346d46..3a9e63ba9f1a 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string> <string name="controls_media_title" msgid="1746947284862928133">"Margmiðlunarefni"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fela núverandi lotu."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fela"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Stillingar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index ef862cb0f919..3eca501b103c 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string> <string name="controls_media_title" msgid="1746947284862928133">"Contenuti multimediali"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Nascondi la sessione attuale."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Nascondi"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Impostazioni"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 358946d69472..e88c951cf19e 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"בטעינת המלצות"</string> <string name="controls_media_title" msgid="1746947284862928133">"מדיה"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"הסתרת הסשן הנוכחי."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"הסתרה"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"הגדרות"</string> <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 9cb872bf1fab..130f682daaf3 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string> <string name="controls_media_title" msgid="1746947284862928133">"メディア"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"現在のセッションを非表示にします。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"非表示"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index ef6ff128ed09..d050875c35ce 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string> <string name="controls_media_title" msgid="1746947284862928133">"მედია"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"დაიმალოს მიმდინარე სესია"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"დამალვა"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"პარამეტრები"</string> <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 08b1f6262f1f..36c726edb791 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string> <string name="controls_media_title" msgid="1746947284862928133">"Мультимедиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ағымдағы сеансты жасыру"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жасыру"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Параметрлер"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 6d80ee47413c..9d87c583c007 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុកការណែនាំ"</string> <string name="controls_media_title" msgid="1746947284862928133">"មេឌៀ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"លាក់វគ្គបច្ចុប្បន្ន។"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"លាក់"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ការកំណត់"</string> <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index db2086458286..901f024c5f71 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ಮಾಧ್ಯಮ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ಪ್ರಸ್ತುತ ಸೆಶನ್ ಅನ್ನು ಮರೆಮಾಡಿ."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ಮರೆಮಾಡಿ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index b43eb410c46d..8a6415566676 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string> <string name="controls_media_title" msgid="1746947284862928133">"미디어"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"현재 세션을 숨깁니다."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"숨기기"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"설정"</string> <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 02e468a4f311..3cf41264a4d4 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Учурдагы сеансты жашыруу."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Жашыруу"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Жөндөөлөр"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string> diff --git a/packages/SystemUI/res/values-land-television/dimens.xml b/packages/SystemUI/res/values-land-television/dimens.xml index 499341c662b1..90fc652b05e9 100644 --- a/packages/SystemUI/res/values-land-television/dimens.xml +++ b/packages/SystemUI/res/values-land-television/dimens.xml @@ -17,5 +17,8 @@ <resources> <!-- Width of volume bar --> <dimen name="volume_dialog_row_width">252dp</dimen> - <dimen name="volume_dialog_tap_target_size">36dp</dimen> + <dimen name="tv_volume_dialog_bubble_size">36dp</dimen> + <dimen name="tv_volume_dialog_corner_radius">40dp</dimen> + <dimen name="tv_volume_dialog_row_padding">5dp</dimen> + <dimen name="tv_volume_number_text_size">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 030bdc1ae120..b1c5a5cd887e 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ມີເດຍ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ເຊື່ອງເຊດຊັນປັດຈຸບັນ."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ເຊື່ອງ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ການຕັ້ງຄ່າ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 6f487416b322..4e9b802f4916 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medija"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Slėpti dabartinį seansą."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Slėpti"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nustatymai"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index bdea26a1a202..a4c4666fafe3 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multivide"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Paslēpiet pašreizējo sesiju."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Paslēpt"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Iestatījumi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index c9f3777c6192..7e623ad5032f 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string> <string name="controls_media_title" msgid="1746947284862928133">"Аудиовизуелни содржини"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Сокриј ја тековнава сесија."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сокриј"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Поставки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index c968c2827437..35e642769981 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string> <string name="controls_media_title" msgid="1746947284862928133">"മീഡിയ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"നിലവിലെ സെഷൻ മറയ്ക്കുക."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"മറയ്ക്കുക"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ക്രമീകരണം"</string> <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 9ce6779e9ae4..b4690d418480 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Одоогийн харилцан үйлдлийг нуугаарай."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Нуух"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Тохиргоо"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index d7126795089f..4ea965ad80fc 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string> <string name="controls_media_title" msgid="1746947284862928133">"मीडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"सध्याचे सेशन लपवा."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लपवा"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिंग्ज"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 01e918ade0ee..38ee25c7f3e4 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Sembunyikan sesi semasa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Sembunyikan"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Tetapan"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 23b0a06cca8f..150ed94eec38 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string> <string name="controls_media_title" msgid="1746947284862928133">"မီဒီယာ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"လက်ရှိ စက်ရှင်ကို ဖျောက်ထားမည်။"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ဖျောက်ထားမည်"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ပယ်ရန်"</string> <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ဆက်တင်များ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index b0a593fe42f9..d872a89880c9 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medier"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skjul den nåværende økten."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skjul"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Innstillinger"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 09462cf3ffcb..1974e8088971 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -731,11 +731,11 @@ <string name="see_more_title" msgid="7409317011708185729">"थप हेर्नुहोस्"</string> <string name="appops_camera" msgid="5215967620896725715">"यो अनुप्रयोगले क्यामेराको प्रयोग गर्दै छ।"</string> <string name="appops_microphone" msgid="8805468338613070149">"यो अनुप्रयोगले माइक्रोफोनको प्रयोग गर्दै छ।"</string> - <string name="appops_overlay" msgid="4822261562576558490">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्दै छ।"</string> + <string name="appops_overlay" msgid="4822261562576558490">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्दै छ।"</string> <string name="appops_camera_mic" msgid="7032239823944420431">"यो अनुप्रयोगले माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> - <string name="appops_camera_overlay" msgid="6466845606058816484">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै क्यामेराको प्रयोग गर्दै छ।"</string> - <string name="appops_mic_overlay" msgid="4609326508944233061">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै माइक्रोफोनको प्रयोग गर्दै छ।"</string> - <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य अनुप्रयोगहरूमाथि प्रदर्शन गर्नुका साथै माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> + <string name="appops_camera_overlay" msgid="6466845606058816484">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै क्यामेराको प्रयोग गर्दै छ।"</string> + <string name="appops_mic_overlay" msgid="4609326508944233061">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै माइक्रोफोनको प्रयोग गर्दै छ।"</string> + <string name="appops_camera_mic_overlay" msgid="5584311236445644095">"यो अनुप्रयोगले तपाईंको स्क्रिनका अन्य एपमाथि प्रदर्शन गर्नुका साथै माइक्रोफोन र क्यामेराको प्रयोग गर्दै छ।"</string> <string name="notification_appops_settings" msgid="5208974858340445174">"सेटिङहरू"</string> <string name="notification_appops_ok" msgid="2177609375872784124">"ठिक छ"</string> <string name="feedback_silenced" msgid="5382212321253328247">"सिस्टमले यो सूचना आउँदा बज्ने ध्वनि बन्द गरेको छ।"</string> @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string> <string name="controls_media_title" msgid="1746947284862928133">"मिडिया"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"हालको सत्र लुकाउनुहोस्।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"लुकाउनुहोस्"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"सेटिङ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string> @@ -1084,8 +1085,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> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <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-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 2385017a0df7..9da8afa4d698 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"De huidige sessie verbergen."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Verbergen"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Instellingen"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index d5c077b3ec1b..5b5cbc62fe21 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string> <string name="controls_media_title" msgid="1746947284862928133">"ମିଡିଆ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ବର୍ତ୍ତମାନର ସେସନ୍ ଲୁଚାନ୍ତୁ।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ଲୁଚାନ୍ତୁ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ସେଟିଂସ୍"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string> @@ -1084,8 +1085,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> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <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-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 11567821397a..5c31ce71ef98 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string> <string name="controls_media_title" msgid="1746947284862928133">"ਮੀਡੀਆ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ਮੌਜੂਦਾ ਸੈਸ਼ਨ ਨੂੰ ਲੁਕਾਓ।"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ਲੁਕਾਓ"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ਸੈਟਿੰਗਾਂ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string> @@ -1084,8 +1085,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> - <!-- no translation found for one_handed_tutorial_title (6312198435090726656) --> - <skip /> - <!-- no translation found for one_handed_tutorial_description (7674850272340517174) --> - <skip /> + <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-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 1f6effe431e7..b7ee75057626 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimedia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ukryj bieżącą sesję."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ukryj"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ustawienia"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 14d7a84dab28..715b0e45faeb 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index a6f7f004f411..1a59de496c91 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Multimédia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Oculte a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Ignorar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Definições"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 14d7a84dab28..715b0e45faeb 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_title" msgid="1746947284862928133">"Mídia"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ocultar a sessão atual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ocultar"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Dispensar"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Configurações"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 0f15cfcd23f6..49c3ba0c2cd8 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ascunde sesiunea actuală."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ascunde"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Setări"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 6196f88a7bfb..7fb456d5f425 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медиа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Скрыть текущий сеанс?"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Скрыть"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Настройки"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 8aca9f4e0dbd..1cd1ceb21c97 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string> <string name="controls_media_title" msgid="1746947284862928133">"මාධ්ය"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"වත්මන් සැසිය සඟවන්න."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"සඟවන්න"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"ඉවත ලන්න"</string> <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"සැකසීම්"</string> <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 45ee562b374c..9d7e7d1cd27c 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string> <string name="controls_media_title" msgid="1746947284862928133">"Médiá"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skryť aktuálnu reláciu."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skryť"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavenia"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index c7ad8ab92da3..ecbf1d905e5b 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string> <string name="controls_media_title" msgid="1746947284862928133">"Predstavnost"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Skrije trenutno sejo."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Skrij"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Nastavitve"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 3e0aecc16d4e..70245b875726 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fshih sesionin aktual."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fshih"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cilësimet"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 985041b3b24d..1d02ca6ab455 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1075,7 +1075,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медији"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Сакријте актуелну сесију."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Сакриј"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Подешавања"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 2018a383b5ed..7a7448be16c5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Dölj den aktuella sessionen."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Dölj"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Inställningar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 6eecc0e402fa..b8d95fcd0c1a 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Maudhui"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ficha kipindi cha sasa."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ficha"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mipangilio"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index a05e0e735620..60c1cf9dcac0 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string> <string name="controls_media_title" msgid="1746947284862928133">"மீடியா"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"இந்த அமர்வை மறையுங்கள்."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"மறை"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"அமைப்புகள்"</string> <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 7d76abd0f20f..6cfe03d95023 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string> <string name="controls_media_title" msgid="1746947284862928133">"మీడియా"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ప్రస్తుత సెషన్ను దాచు."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"దాచు"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"సెట్టింగ్లు"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 1696aab66148..7b1479acc35e 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -43,4 +43,7 @@ <item>com.android.systemui.toast.ToastUI</item> <item>com.android.systemui.onehanded.OneHandedUI</item> </string-array> + + <!-- Show a separate icon for low and high volume on the volume dialog --> + <bool name="config_showLowMediaVolumeIcon">true</bool> </resources> diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml index b01c5d88e3b3..4cf7034a29bf 100644 --- a/packages/SystemUI/res/values-television/styles.xml +++ b/packages/SystemUI/res/values-television/styles.xml @@ -22,4 +22,8 @@ <item name="android:windowEnterAnimation">@null</item> <item name="android:windowExitAnimation">@null</item> </style> + + <style name="volume_dialog_theme" parent="qs_theme"> + <item name="android:colorAccent">@color/tv_volume_dialog_accent</item> + </style> </resources> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 765c22424e89..a2c1127df5ca 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string> <string name="controls_media_title" msgid="1746947284862928133">"สื่อ"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"ซ่อนเซสชันปัจจุบัน"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"ซ่อน"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"การตั้งค่า"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index c2cae9024a60..e5f0532b0e7b 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Itago ang kasalukuyang session."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Itago"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Mga Setting"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 74b44f2079c6..4943e2d03920 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string> <string name="controls_media_title" msgid="1746947284862928133">"Medya"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Mevcut oturumu gizle."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Gizle"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Ayarlar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 38c331ade344..447912e08835 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1081,7 +1081,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string> <string name="controls_media_title" msgid="1746947284862928133">"Медіа"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Приховати поточний сеанс."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Приховати"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Налаштування"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 69ddabbe94ac..20b551882344 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string> <string name="controls_media_title" msgid="1746947284862928133">"میڈیا"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"موجودہ سیشن چھپائیں۔"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"چھپائیں"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"ترتیبات"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index ed704b0f5597..cf1da7508052 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -227,7 +227,7 @@ <string name="data_connection_roaming" msgid="375650836665414797">"Rouming"</string> <string name="data_connection_edge" msgid="6316755666481405762">"EDGE"</string> <string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string> - <string name="accessibility_no_sim" msgid="1140839832913084973">"SIM karta solinmagan."</string> + <string name="accessibility_no_sim" msgid="1140839832913084973">"SIM kartasiz."</string> <string name="accessibility_cell_data" msgid="172950885786007392">"Mobil internet"</string> <string name="accessibility_cell_data_on" msgid="691666434519443162">"Mobil internet yoniq"</string> <string name="cell_data_off_content_description" msgid="9165555931499878044">"Mobil internet yoqilmagan"</string> @@ -1069,7 +1069,7 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string> <string name="controls_media_title" msgid="1746947284862928133">"Media"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Joriy seans berkitilsin."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Berkitish"</string> + <string name="controls_media_dismiss_button" msgid="9081375542265132213">"Yopish"</string> <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Sozlamalar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 5cc209941771..a12a08d0a1e6 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string> <string name="controls_media_title" msgid="1746947284862928133">"Nội dung nghe nhìn"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Ẩn phiên hiện tại."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ẩn"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Cài đặt"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index f670bf682b64..3382365b7ccb 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒体"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隐藏当前会话。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隐藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"设置"</string> <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 2e26d6153a8f..1d55ca22a43f 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隱藏目前的工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0049d2ec1f56..e62c164684b3 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string> <string name="controls_media_title" msgid="1746947284862928133">"媒體"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"隱藏目前的工作階段。"</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"隱藏"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"設定"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index c8c99b1c18c1..bd7391203dd8 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1069,7 +1069,8 @@ <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string> <string name="controls_media_title" msgid="1746947284862928133">"Imidiya"</string> <string name="controls_media_close_session" msgid="3957093425905475065">"Fihla iseshini yamanje."</string> - <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Fihla"</string> + <!-- no translation found for controls_media_dismiss_button (9081375542265132213) --> + <skip /> <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string> <string name="controls_media_settings_button" msgid="5815790345117172504">"Izilungiselelo"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string> diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml index 53cd9716c98e..cb49918e4e3f 100644 --- a/packages/SystemUI/res/values/colors_tv.xml +++ b/packages/SystemUI/res/values/colors_tv.xml @@ -24,7 +24,11 @@ <!-- Background color for audio recording indicator (G800) --> <color name="tv_audio_recording_indicator_background">#FF3C4043</color> - <color name="tv_audio_recording_indicator_pulse">#4DFFFFFF</color> + <color name="tv_audio_recording_indicator_icon_background">#CC000000</color> + <color name="tv_audio_recording_indicator_stroke">#33FFFFFF</color> <color name="red">#FFCC0000</color> + <color name="tv_volume_dialog_background">#E61F232B</color> + <color name="tv_volume_dialog_circle">#08FFFFFF</color> + <color name="tv_volume_dialog_accent">#FFDADCE0</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index fba43a628387..17ba7c99dc0c 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -574,4 +574,6 @@ <!-- Animation duration for translating of one handed when trigger / dismiss. --> <integer name="config_one_handed_translate_animation_duration">150</integer> + <!-- Show a separate icon for low and high volume on the volume dialog --> + <bool name="config_showLowMediaVolumeIcon">false</bool> </resources> diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml index 67293c57e344..f05be066d2e2 100644 --- a/packages/SystemUI/res/values/donottranslate.xml +++ b/packages/SystemUI/res/values/donottranslate.xml @@ -21,5 +21,5 @@ <string name="system_ui_date_pattern" translatable="false">@*android:string/system_ui_date_pattern</string> <!-- Date format for the always on display. --> - <item type="string" name="system_ui_aod_date_pattern" translatable="false">eeeMMMd</item> + <item type="string" name="system_ui_aod_date_pattern" translatable="false">EEEMMMd</item> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 9e5b94ee855c..ee07e613a0c5 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -387,6 +387,9 @@ <item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item> </style> + <!-- Overridden by values-television/styles.xml with tv-specific settings --> + <style name="volume_dialog_theme" parent="qs_theme"/> + <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light"> <item name="android:colorAccent">@color/remote_input_accent</item> </style> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java index 4d968f1763ca..73dc60dbc7da 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperEngineCompat.java @@ -26,6 +26,17 @@ public class WallpaperEngineCompat { private static final String TAG = "WallpaperEngineCompat"; + /** + * Returns true if {@link IWallpaperEngine#scalePreview(Rect)} is available. + */ + public static boolean supportsScalePreview() { + try { + return IWallpaperEngine.class.getMethod("scalePreview", Rect.class) != null; + } catch (NoSuchMethodException | SecurityException e) { + return false; + } + } + private final IWallpaperEngine mWrappedEngine; public WallpaperEngineCompat(IWallpaperEngine wrappedEngine) { diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt b/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt index 8b953fa46441..be089b12a95d 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt @@ -21,7 +21,7 @@ import com.android.internal.logging.UiEventLogger enum class AssistantSessionEvent(private val id: Int) : UiEventLogger.UiEventEnum { @UiEvent(doc = "Unknown assistant session event") - ASSISTANT_SESSION_UNKNOWN(523), + ASSISTANT_SESSION_UNKNOWN(0), @UiEvent(doc = "Assistant session dismissed due to timeout") ASSISTANT_SESSION_TIMEOUT_DISMISS(524), diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java index 95bbea15a88c..d4e6506bd9a0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; +import android.annotation.NonNull; import android.content.Context; import android.os.UserHandle; import android.text.InputType; @@ -27,7 +28,9 @@ import android.widget.ImeAwareEditText; import android.widget.TextView; import com.android.internal.widget.LockPatternChecker; +import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.systemui.R; /** @@ -104,18 +107,21 @@ public class AuthCredentialPasswordView extends AuthCredentialView return; } + // Request LockSettingsService to return the Gatekeeper Password in the + // VerifyCredentialResponse so that we can request a Gatekeeper HAT with the + // Gatekeeper Password and operationId. mPendingLockCheck = LockPatternChecker.verifyCredential(mLockPatternUtils, - password, mOperationId, mEffectiveUserId, this::onCredentialVerified); + password, mEffectiveUserId, LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW, + this::onCredentialVerified); } } @Override - protected void onCredentialVerified(byte[] attestation, int timeoutMs) { - super.onCredentialVerified(attestation, timeoutMs); + protected void onCredentialVerified(@NonNull VerifyCredentialResponse response, + int timeoutMs) { + super.onCredentialVerified(response, timeoutMs); - final boolean matched = attestation != null; - - if (matched) { + if (response.isMatched()) { mImm.hideSoftInputFromWindow(getWindowToken(), 0 /* flags */); } else { mPasswordField.setText(""); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java index 6d16f4397115..ad89ae82f637 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java @@ -16,6 +16,7 @@ package com.android.systemui.biometrics; +import android.annotation.NonNull; import android.content.Context; import android.util.AttributeSet; @@ -23,6 +24,7 @@ import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockscreenCredential; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.systemui.R; import java.util.List; @@ -61,22 +63,25 @@ public class AuthCredentialPatternView extends AuthCredentialView { if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) { // Pattern size is less than the minimum, do not count it as a failed attempt. - onPatternVerified(null /* attestation */, 0 /* timeoutMs */); + onPatternVerified(VerifyCredentialResponse.ERROR, 0 /* timeoutMs */); return; } try (LockscreenCredential credential = LockscreenCredential.createPattern(pattern)) { + // Request LockSettingsService to return the Gatekeeper Password in the + // VerifyCredentialResponse so that we can request a Gatekeeper HAT with the + // Gatekeeper Password and operationId. mPendingLockCheck = LockPatternChecker.verifyCredential( mLockPatternUtils, credential, - mOperationId, mEffectiveUserId, + LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW, this::onPatternVerified); } } - private void onPatternVerified(byte[] attestation, int timeoutMs) { - AuthCredentialPatternView.this.onCredentialVerified(attestation, timeoutMs); + private void onPatternVerified(@NonNull VerifyCredentialResponse response, int timeoutMs) { + AuthCredentialPatternView.this.onCredentialVerified(response, timeoutMs); if (timeoutMs > 0) { mLockPatternView.setEnabled(false); } else { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java index 2695c69056b1..a8f6f85201f6 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java @@ -16,6 +16,9 @@ package com.android.systemui.biometrics; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; import android.content.Context; @@ -38,12 +41,10 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.annotation.IntDef; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import androidx.annotation.StringRes; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.VerifyCredentialResponse; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -283,14 +284,18 @@ public abstract class AuthCredentialView extends LinearLayout { protected void onErrorTimeoutFinish() {} - protected void onCredentialVerified(byte[] attestation, int timeoutMs) { - - final boolean matched = attestation != null; - - if (matched) { + protected void onCredentialVerified(@NonNull VerifyCredentialResponse response, int timeoutMs) { + if (response.isMatched()) { mClearErrorRunnable.run(); mLockPatternUtils.userPresent(mEffectiveUserId); - mCallback.onCredentialMatched(attestation); + + // The response passed into this method contains the Gatekeeper Password. We still + // have to request Gatekeeper to create a Hardware Auth Token with the + // Gatekeeper Password and Challenge (keystore operationId in this case) + final VerifyCredentialResponse gkResponse = mLockPatternUtils.verifyGatekeeperPassword( + response.getGatekeeperPw(), mOperationId, mEffectiveUserId); + + mCallback.onCredentialMatched(gkResponse.getGatekeeperHAT()); } else { if (timeoutMs > 0) { mHandler.removeCallbacks(mClearErrorRunnable); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index fce545b421d5..f774358b69fb 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -38,6 +38,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.people.PeopleHubModule; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.KeyguardLiftController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; @@ -72,7 +73,8 @@ import dagger.Provides; subcomponents = {StatusBarComponent.class, NotificationRowComponent.class, DozeComponent.class, - ExpandableNotificationRowComponent.class}) + ExpandableNotificationRowComponent.class, + NotificationShelfComponent.class}) public abstract class SystemUIModule { @Binds 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/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java index f8655cc44d2a..52a2cecec6b1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java @@ -3,7 +3,9 @@ package com.android.systemui.qs; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; +import android.graphics.drawable.Animatable2; import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -44,6 +46,24 @@ public class PageIndicator extends ViewGroup { private int mPosition = -1; private boolean mAnimating; + private final Animatable2.AnimationCallback mAnimationCallback = + new Animatable2.AnimationCallback() { + + @Override + public void onAnimationEnd(Drawable drawable) { + super.onAnimationEnd(drawable); + if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size()); + if (drawable instanceof AnimatedVectorDrawable) { + ((AnimatedVectorDrawable) drawable).unregisterAnimationCallback( + mAnimationCallback); + } + mAnimating = false; + if (mQueuedPositions.size() != 0) { + setPosition(mQueuedPositions.remove(0)); + } + } + }; + public PageIndicator(Context context, AttributeSet attrs) { super(context, attrs); @@ -197,10 +217,8 @@ public class PageIndicator extends ViewGroup { final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext().getDrawable(res); imageView.setImageDrawable(avd); avd.forceAnimationOnUI(); + avd.registerAnimationCallback(mAnimationCallback); avd.start(); - // TODO: Figure out how to user an AVD animation callback instead, which doesn't - // seem to be working right now... - postDelayed(mAnimationDone, ANIMATION_DURATION); } private int getTransition(boolean fromB, boolean isMajorAState, boolean isMajor) { @@ -264,15 +282,4 @@ public class PageIndicator extends ViewGroup { getChildAt(i).layout(left, 0, mPageIndicatorWidth + left, mPageIndicatorHeight); } } - - private final Runnable mAnimationDone = new Runnable() { - @Override - public void run() { - if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size()); - mAnimating = false; - if (mQueuedPositions.size() != 0) { - setPosition(mQueuedPositions.remove(0)); - } - } - }; } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index c53523032353..6747281ac437 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -50,6 +50,7 @@ import android.graphics.drawable.LayerDrawable; import android.media.MediaActionSound; import android.net.Uri; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -556,11 +557,18 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset private void takeScreenshotInternal(Consumer<Uri> finisher, Rect crop) { // copy the input Rect, since SurfaceControl.screenshot can mutate it Rect screenRect = new Rect(crop); - int rot = mDisplay.getRotation(); int width = crop.width(); int height = crop.height(); - saveScreenshot(SurfaceControl.screenshot(crop, width, height, rot), finisher, screenRect, - Insets.NONE, true); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setSourceCrop(crop) + .setSize(width, height) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap screenshot = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); + saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, true); } private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect, 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/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index d798692879f5..36f8bcdc9123 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -18,7 +18,6 @@ package com.android.systemui.statusbar; import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN_REVERSE; import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE; -import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT; import android.content.Context; import android.content.res.Configuration; @@ -26,7 +25,6 @@ import android.content.res.Resources; import android.graphics.Rect; import android.os.SystemProperties; import android.util.AttributeSet; -import android.util.Log; import android.util.MathUtils; import android.view.DisplayCutout; import android.view.View; @@ -36,10 +34,8 @@ import android.view.WindowInsets; import android.view.accessibility.AccessibilityNodeInfo; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -50,12 +46,8 @@ import com.android.systemui.statusbar.notification.stack.AnimationProperties; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.ViewState; -import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationIconContainer; -import javax.inject.Inject; -import javax.inject.Named; - /** * A notification shelf view that is placed inside the notification scroller. It manages the * overflow icons that don't fit into the regular list anymore. @@ -69,7 +61,6 @@ public class NotificationShelf extends ActivatableNotificationView implements = SystemProperties.getBoolean("debug.icon_scroll_animations", true); private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag; private static final String TAG = "NotificationShelf"; - private final KeyguardBypassController mBypassController; private NotificationIconContainer mShelfIcons; private int[] mTmp = new int[2]; @@ -77,7 +68,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mIconAppearTopPadding; private float mHiddenShelfIconSize; private int mStatusBarHeight; - private int mStatusBarPaddingStart; private AmbientState mAmbientState; private NotificationStackScrollLayout mHostLayout; private int mMaxLayoutHeight; @@ -88,7 +78,6 @@ public class NotificationShelf extends ActivatableNotificationView implements private int mScrollFastThreshold; private int mIconSize; private int mStatusBarState; - private float mMaxShelfEnd; private int mRelativeOffset; private boolean mInteractive; private float mOpenedAmount; @@ -99,13 +88,10 @@ public class NotificationShelf extends ActivatableNotificationView implements private Rect mClipRect = new Rect(); private int mCutoutHeight; private int mGapHeight; + private NotificationShelfController mController; - @Inject - public NotificationShelf(@Named(VIEW_CONTEXT) Context context, - AttributeSet attrs, - KeyguardBypassController keyguardBypassController) { + public NotificationShelf(Context context, AttributeSet attrs) { super(context, attrs); - mBypassController = keyguardBypassController; } @Override @@ -128,19 +114,6 @@ public class NotificationShelf extends ActivatableNotificationView implements initDimens(); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class)) - .addCallback(this, SysuiStatusBarStateController.RANK_SHELF); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Dependency.get(StatusBarStateController.class).removeCallback(this); - } - public void bind(AmbientState ambientState, NotificationStackScrollLayout hostLayout) { mAmbientState = ambientState; mHostLayout = hostLayout; @@ -150,7 +123,6 @@ public class NotificationShelf extends ActivatableNotificationView implements Resources res = getResources(); mIconAppearTopPadding = res.getDimensionPixelSize(R.dimen.notification_icon_appear_padding); mStatusBarHeight = res.getDimensionPixelOffset(R.dimen.status_bar_height); - mStatusBarPaddingStart = res.getDimensionPixelOffset(R.dimen.status_bar_padding_start); mPaddingBetweenElements = res.getDimensionPixelSize(R.dimen.notification_divider_height); ViewGroup.LayoutParams layoutParams = getLayoutParams(); @@ -315,9 +287,7 @@ public class NotificationShelf extends ActivatableNotificationView implements transitionAmount = inShelfAmount; } // We don't want to modify the color if the notification is hun'd - boolean canModifyColor = mAmbientState.isShadeExpanded() - && !(mAmbientState.isOnKeyguard() && mBypassController.getBypassEnabled()); - if (isLastChild && canModifyColor) { + if (isLastChild && mController.canModifyColorOfNotifications()) { if (colorOfViewBeforeLast == NO_COLOR) { colorOfViewBeforeLast = ownColorUntinted; } @@ -999,10 +969,6 @@ public class NotificationShelf extends ActivatableNotificationView implements return mInteractive; } - public void setMaxShelfEnd(float maxShelfEnd) { - mMaxShelfEnd = maxShelfEnd; - } - public void setAnimationsEnabled(boolean enabled) { mAnimationsEnabled = enabled; if (!enabled) { @@ -1044,6 +1010,10 @@ public class NotificationShelf extends ActivatableNotificationView implements updateBackgroundColors(); } + public void setController(NotificationShelfController notificationShelfController) { + mController = notificationShelfController; + } + private class ShelfState extends ExpandableViewState { private float openedAmount; private boolean hasItemsInStableShelf; @@ -1056,7 +1026,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.applyToView(view); - setMaxShelfEnd(maxShelfEnd); setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); @@ -1070,7 +1039,6 @@ public class NotificationShelf extends ActivatableNotificationView implements } super.animateTo(child, properties); - setMaxShelfEnd(maxShelfEnd); setOpenedAmount(openedAmount); updateAppearance(); setHasItemsInStableShelf(hasItemsInStableShelf); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java new file mode 100644 index 000000000000..9f8f8447d72c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelfController.java @@ -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.systemui.statusbar; + +import android.view.View; + +import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; +import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope; +import com.android.systemui.statusbar.notification.stack.AmbientState; +import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationIconContainer; +import com.android.systemui.statusbar.phone.StatusBarNotificationPresenter; + +import javax.inject.Inject; + +/** + * Controller class for {@link NotificationShelf}. + */ +@NotificationRowScope +public class NotificationShelfController { + private final NotificationShelf mView; + private final ActivatableNotificationViewController mActivatableNotificationViewController; + private final KeyguardBypassController mKeyguardBypassController; + private final SysuiStatusBarStateController mStatusBarStateController; + private final View.OnAttachStateChangeListener mOnAttachStateChangeListener; + private AmbientState mAmbientState; + + @Inject + public NotificationShelfController(NotificationShelf notificationShelf, + ActivatableNotificationViewController activatableNotificationViewController, + KeyguardBypassController keyguardBypassController, + SysuiStatusBarStateController statusBarStateController) { + mView = notificationShelf; + mActivatableNotificationViewController = activatableNotificationViewController; + mKeyguardBypassController = keyguardBypassController; + mStatusBarStateController = statusBarStateController; + mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + mStatusBarStateController.addCallback( + mView, SysuiStatusBarStateController.RANK_SHELF); + } + + @Override + public void onViewDetachedFromWindow(View v) { + mStatusBarStateController.removeCallback(mView); + } + }; + } + + public void init() { + mActivatableNotificationViewController.init(); + mView.setController(this); + mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + if (mView.isAttachedToWindow()) { + mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + } + } + + public NotificationShelf getView() { + return mView; + } + + public boolean canModifyColorOfNotifications() { + return mAmbientState.isShadeExpanded() + && !(mAmbientState.isOnKeyguard() && mKeyguardBypassController.getBypassEnabled()); + } + + public NotificationIconContainer getShelfIcons() { + return mView.getShelfIcons(); + } + + public void setCollapsedIcons(NotificationIconContainer notificationIcons) { + mView.setCollapsedIcons(notificationIcons); + } + + public void bind(AmbientState ambientState, + NotificationStackScrollLayout notificationStackScrollLayout) { + mView.bind(ambientState, notificationStackScrollLayout); + mAmbientState = ambientState; + } + + public int getHeight() { + return mView.getHeight(); + } + + public void updateState(AmbientState ambientState) { + mAmbientState = ambientState; + mView.updateState(ambientState); + } + + public int getIntrinsicHeight() { + return mView.getIntrinsicHeight(); + } + + public void setOnActivatedListener(StatusBarNotificationPresenter presenter) { + mView.setOnActivatedListener(presenter); + } + + public void setOnClickListener(View.OnClickListener onClickListener) { + mView.setOnClickListener(onClickListener); + } + + public int getNotGoneIndex() { + return mView.getNotGoneIndex(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java index 7cda23544ca0..27e4adee68ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SuperStatusBarViewFactory.java @@ -21,7 +21,7 @@ import android.view.LayoutInflater; import android.view.ViewGroup; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.LockIcon; import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.NotificationPanelView; @@ -41,22 +41,22 @@ public class SuperStatusBarViewFactory { private final Context mContext; private final InjectionInflationController mInjectionInflationController; - private final NotificationRowComponent.Builder mNotificationRowComponentBuilder; private final LockscreenLockIconController mLockIconController; + private final NotificationShelfComponent.Builder mNotificationShelfComponentBuilder; private NotificationShadeWindowView mNotificationShadeWindowView; private StatusBarWindowView mStatusBarWindowView; - private NotificationShelf mNotificationShelf; + private NotificationShelfController mNotificationShelfController; @Inject public SuperStatusBarViewFactory(Context context, InjectionInflationController injectionInflationController, - NotificationRowComponent.Builder notificationRowComponentBuilder, + NotificationShelfComponent.Builder notificationShelfComponentBuilder, LockscreenLockIconController lockIconController) { mContext = context; mInjectionInflationController = injectionInflationController; - mNotificationRowComponentBuilder = notificationRowComponentBuilder; mLockIconController = lockIconController; + mNotificationShelfComponentBuilder = notificationShelfComponentBuilder; } /** @@ -114,25 +114,27 @@ public class SuperStatusBarViewFactory { * isn't immediately attached, but the layout params of this view is used * during inflation. */ - public NotificationShelf getNotificationShelf(ViewGroup container) { - if (mNotificationShelf != null) { - return mNotificationShelf; + public NotificationShelfController getNotificationShelfController(ViewGroup container) { + if (mNotificationShelfController != null) { + return mNotificationShelfController; } - mNotificationShelf = (NotificationShelf) mInjectionInflationController.injectable( - LayoutInflater.from(mContext)).inflate(R.layout.status_bar_notification_shelf, - container, /* attachToRoot= */ false); + NotificationShelf view = (NotificationShelf) LayoutInflater.from(mContext) + .inflate(R.layout.status_bar_notification_shelf, container, /* attachToRoot= */ + false); - NotificationRowComponent component = mNotificationRowComponentBuilder - .activatableNotificationView(mNotificationShelf) - .build(); - component.getActivatableNotificationViewController().init(); - - if (mNotificationShelf == null) { + if (view == null) { throw new IllegalStateException( "R.layout.status_bar_notification_shelf could not be properly inflated"); } - return mNotificationShelf; + + NotificationShelfComponent component = mNotificationShelfComponentBuilder + .notificationShelf(view) + .build(); + mNotificationShelfController = component.getNotificationShelfController(); + mNotificationShelfController.init(); + + return mNotificationShelfController; } public NotificationPanelView getNotificationPanelView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java new file mode 100644 index 000000000000..af8d6ec727d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/NotificationShelfComponent.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.row.dagger; + +import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; +import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; + +import dagger.Binds; +import dagger.BindsInstance; +import dagger.Module; +import dagger.Subcomponent; + +/** + * Dagger subcomponent for NotificationShelf. + */ +@Subcomponent(modules = {ActivatableNotificationViewModule.class, + NotificationShelfComponent.NotificationShelfModule.class}) +@NotificationRowScope +public interface NotificationShelfComponent { + /** + * Builder for {@link NotificationShelfComponent}. + */ + @Subcomponent.Builder + interface Builder { + @BindsInstance + Builder notificationShelf(NotificationShelf view); + NotificationShelfComponent build(); + } + + /** + * Creates a NotificationShelfController. + */ + @NotificationRowScope + NotificationShelfController getNotificationShelfController(); + /** + * Dagger Module that extracts interesting properties from a NotificationShelf. + */ + @Module + abstract class NotificationShelfModule { + + /** NotificationShelf is provided as an instance of ActivatableNotificationView. */ + @Binds + abstract ActivatableNotificationView bindNotificationShelf(NotificationShelf view); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 66a541a923a4..57c1a16a259d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -113,6 +113,7 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -5419,28 +5420,23 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public void setShelf(NotificationShelf shelf) { + public void setShelfController(NotificationShelfController notificationShelfController) { int index = -1; if (mShelf != null) { index = indexOfChild(mShelf); removeView(mShelf); } - mShelf = shelf; + mShelf = notificationShelfController.getView(); addView(mShelf, index); - mAmbientState.setShelf(shelf); - mStateAnimator.setShelf(shelf); - shelf.bind(mAmbientState, this); + mAmbientState.setShelf(mShelf); + mStateAnimator.setShelf(mShelf); + notificationShelfController.bind(mAmbientState, this); if (ANCHOR_SCROLLING) { mScrollAnchorView = mShelf; } } @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) - public NotificationShelf getNotificationShelf() { - return mShelf; - } - - @ShadeViewRefactor(RefactorComponent.SHADE_VIEW) public void setMaxDisplayedNotifications(int maxDisplayedNotifications) { if (mMaxDisplayedNotifications != maxDisplayedNotifications) { mMaxDisplayedNotifications = maxDisplayedNotifications; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java index 687f5f15a78c..8a85f7d6a2c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java @@ -30,6 +30,8 @@ import com.android.systemui.R; import com.android.systemui.statusbar.policy.KeyButtonDrawable; import com.android.systemui.statusbar.policy.KeyButtonView; +import java.util.function.Consumer; + /** Containing logic for the rotation button on the physical left bottom corner of the screen. */ public class FloatingRotationButton implements RotationButton { @@ -45,6 +47,7 @@ public class FloatingRotationButton implements RotationButton { private boolean mCanShow = true; private RotationButtonController mRotationButtonController; + private Consumer<Boolean> mVisibilityChangedCallback; FloatingRotationButton(Context context) { mContext = context; @@ -67,6 +70,11 @@ public class FloatingRotationButton implements RotationButton { } @Override + public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { + mVisibilityChangedCallback = visibilityChangedCallback; + } + + @Override public View getCurrentView() { return mKeyButtonView; } @@ -105,6 +113,16 @@ public class FloatingRotationButton implements RotationButton { mKeyButtonDrawable.resetAnimation(); mKeyButtonDrawable.startAnimation(); } + mKeyButtonView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, + int i6, int i7) { + if (mIsShowing && mVisibilityChangedCallback != null) { + mVisibilityChangedCallback.accept(true); + } + mKeyButtonView.removeOnLayoutChangeListener(this); + } + }); return true; } @@ -115,6 +133,9 @@ public class FloatingRotationButton implements RotationButton { } mWindowManager.removeViewImmediate(mKeyButtonView); mIsShowing = false; + if (mVisibilityChangedCallback != null) { + mVisibilityChangedCallback.accept(false); + } return true; } 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 8c5e2ceaeadf..fd653b4e8aa5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -120,7 +120,6 @@ import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CommandQueue.Callbacks; -import com.android.systemui.statusbar.NavigationBarController; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; @@ -132,7 +131,6 @@ import com.android.systemui.util.LifecycleFragment; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.ref.WeakReference; import java.util.List; import java.util.Locale; import java.util.Optional; @@ -194,6 +192,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback private int mLayoutDirection; private boolean mForceNavBarHandleOpaque; + private boolean mIsCurrentUserSetup; /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int) */ private @Appearance int mAppearance; @@ -313,6 +312,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback @Override public void onNavBarButtonAlphaChanged(float alpha, boolean animate) { + if (!mIsCurrentUserSetup) { + // If the current user is not yet setup, then don't update any button alphas + return; + } ButtonDispatcher buttonDispatcher = null; boolean forceVisible = false; if (QuickStepContract.isSwipeUpMode(mNavBarMode)) { @@ -351,15 +354,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; - private final ContextButtonListener mRotationButtonListener = (button, visible) -> { - if (visible) { - // If the button will actually become visible and the navbar is about to hide, - // tell the statusbar to keep it around for longer - mAutoHideController.touchAutoHide(); - mNavigationBarView.notifyActiveTouchRegions(); - } - }; - private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true); private final ContentObserver mAssistContentObserver = new ContentObserver( @@ -414,6 +408,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; + private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener = + new DeviceProvisionedController.DeviceProvisionedListener() { + @Override + public void onUserSetupChanged() { + mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); + } + }; + @Inject public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper, DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger, @@ -481,6 +483,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback /* defaultValue = */ true); DeviceConfig.addOnPropertiesChangedListener( DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, mOnPropertiesChangedListener); + + mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); + mDeviceProvisionedController.addCallback(mUserSetupListener); } @Override @@ -489,6 +494,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mNavigationModeController.removeListener(this); mAccessibilityManagerWrapper.removeCallback(mAccessibilityListener); mContentResolver.unregisterContentObserver(mAssistContentObserver); + mDeviceProvisionedController.removeCallback(mUserSetupListener); DeviceConfig.removeOnPropertiesChangedListener(mOnPropertiesChangedListener); } @@ -535,8 +541,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback // Currently there is no accelerometer sensor on non-default display. if (mIsOnDefaultDisplay) { - mNavigationBarView.getRotateSuggestionButton().setListener(mRotationButtonListener); - final RotationButtonController rotationButtonController = mNavigationBarView.getRotationButtonController(); rotationButtonController.addRotationCallback(mRotationWatcher); @@ -1340,6 +1344,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (mAutoHideController != null) { mAutoHideController.setNavigationBar(mAutoHideUiElement); } + mNavigationBarView.setAutoHideController(autoHideController); } private boolean isTransientShown() { 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 0b4a2b69ffb3..e3cb105ba2f7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -131,6 +131,7 @@ public class NavigationBarView extends FrameLayout implements private boolean mDeadZoneConsuming = false; private final NavigationBarTransitions mBarTransitions; private final OverviewProxyService mOverviewProxyService; + private AutoHideController mAutoHideController; // performs manual animation in sync with layout transitions private final NavTransitionListener mTransitionListener = new NavTransitionListener(); @@ -276,6 +277,15 @@ public class NavigationBarView extends FrameLayout implements info.touchableRegion.setEmpty(); }; + private final Consumer<Boolean> mRotationButtonListener = (visible) -> { + if (visible) { + // If the button will actually become visible and the navbar is about to hide, + // tell the statusbar to keep it around for longer + mAutoHideController.touchAutoHide(); + } + notifyActiveTouchRegions(); + }; + public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); @@ -313,7 +323,8 @@ public class NavigationBarView extends FrameLayout implements mFloatingRotationButton = new FloatingRotationButton(context); mRotationButtonController = new RotationButtonController(mLightContext, mLightIconColor, mDarkIconColor, - isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton); + isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton, + mRotationButtonListener); mConfiguration = new Configuration(); mTmpLastConfiguration = new Configuration(); @@ -361,6 +372,10 @@ public class NavigationBarView extends FrameLayout implements }); } + public void setAutoHideController(AutoHideController autoHideController) { + mAutoHideController = autoHideController; + } + public NavigationBarTransitions getBarTransitions() { return mBarTransitions; } @@ -939,7 +954,15 @@ public class NavigationBarView extends FrameLayout implements updateButtonLocation(getBackButton()); updateButtonLocation(getHomeButton()); updateButtonLocation(getRecentsButton()); - updateButtonLocation(getRotateSuggestionButton()); + updateButtonLocation(getImeSwitchButton()); + updateButtonLocation(getAccessibilityButton()); + if (mFloatingRotationButton.isVisible()) { + View floatingRotationView = mFloatingRotationButton.getCurrentView(); + floatingRotationView.getBoundsOnScreen(mTmpBounds); + mActiveRegion.op(mTmpBounds, Op.UNION); + } else { + updateButtonLocation(getRotateSuggestionButton()); + } mOverviewProxyService.onActiveNavBarRegionChanges(mActiveRegion); } @@ -1211,6 +1234,7 @@ public class NavigationBarView extends FrameLayout implements dumpButton(pw, "rcnt", getRecentsButton()); dumpButton(pw, "rota", getRotateSuggestionButton()); dumpButton(pw, "a11y", getAccessibilityButton()); + dumpButton(pw, "ime", getImeSwitchButton()); pw.println(" }"); pw.println(" mScreenOn: " + mScreenOn); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 9d3e915cad69..7bbe1c986249 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -26,7 +26,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationMediaManager; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationUtils; @@ -160,9 +160,9 @@ public class NotificationIconAreaController implements DarkReceiver, } } - public void setupShelf(NotificationShelf shelf) { - mShelfIcons = shelf.getShelfIcons(); - shelf.setCollapsedIcons(mNotificationIcons); + public void setupShelf(NotificationShelfController notificationShelfController) { + mShelfIcons = notificationShelfController.getShelfIcons(); + notificationShelfController.setCollapsedIcons(mNotificationIcons); } public void onDensityOrFontScaleChanged(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index a87311a69ab5..6946346eee2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -86,6 +86,7 @@ import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; @@ -454,6 +455,7 @@ public class NotificationPanelViewController extends PanelViewController { private boolean mAnimatingQS; private int mOldLayoutDirection; + private NotificationShelfController mNotificationShelfController; private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() { @Override @@ -858,7 +860,7 @@ public class NotificationPanelViewController extends PanelViewController { float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding(); int notificationPadding = Math.max( 1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height)); - NotificationShelf shelf = mNotificationStackScroller.getNotificationShelf(); + NotificationShelf shelf = mNotificationShelfController.getView(); float shelfSize = shelf.getVisibility() == View.GONE ? 0 @@ -3053,7 +3055,7 @@ public class NotificationPanelViewController extends PanelViewController { } public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager, - NotificationShelf notificationShelf, + NotificationShelfController notificationShelfController, NotificationIconAreaController notificationIconAreaController, ScrimController scrimController) { setStatusBar(statusBar); @@ -3062,9 +3064,10 @@ public class NotificationPanelViewController extends PanelViewController { mNotificationStackScroller.setIconAreaController(notificationIconAreaController); mNotificationStackScroller.setStatusBar(statusBar); mNotificationStackScroller.setGroupManager(groupManager); - mNotificationStackScroller.setShelf(notificationShelf); + mNotificationStackScroller.setShelfController(notificationShelfController); mNotificationStackScroller.setScrimController(scrimController); updateShowEmptyShadeView(); + mNotificationShelfController = notificationShelfController; } public void showTransientIndication(int id) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java index 687efd34ee30..74d4eb175ac4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButton.java @@ -20,9 +20,12 @@ import android.view.View; import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import java.util.function.Consumer; + /** Interface of a rotation button that interacts {@link RotationButtonController}. */ interface RotationButton { void setRotationButtonController(RotationButtonController rotationButtonController); + void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback); View getCurrentView(); boolean show(); boolean hide(); 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 b0630a649ffe..2f2e1f9a1f2e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java @@ -124,7 +124,8 @@ public class RotationButtonController { } RotationButtonController(Context context, @ColorInt int lightIconColor, - @ColorInt int darkIconColor, RotationButton rotationButton) { + @ColorInt int darkIconColor, RotationButton rotationButton, + Consumer<Boolean> visibilityChangedCallback) { mContext = context; mLightIconColor = lightIconColor; mDarkIconColor = darkIconColor; @@ -139,6 +140,7 @@ public class RotationButtonController { mTaskStackListener = new TaskStackListenerImpl(); mRotationButton.setOnClickListener(this::onRotateSuggestionClick); mRotationButton.setOnHoverListener(this::onRotateSuggestionHover); + mRotationButton.setVisibilityChangedCallback(visibilityChangedCallback); } void registerListeners() { 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 08aeb0425f68..d63d445d8ba3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java @@ -23,6 +23,8 @@ import android.view.View; import com.android.systemui.statusbar.policy.KeyButtonDrawable; +import java.util.function.Consumer; + /** Containing logic for the rotation button in nav bar. */ public class RotationContextButton extends ContextualButton implements RotationButton { public static final boolean DEBUG_ROTATION = false; @@ -43,6 +45,18 @@ public class RotationContextButton extends ContextualButton implements RotationB } @Override + public void setVisibilityChangedCallback(Consumer<Boolean> visibilityChangedCallback) { + setListener(new ContextButtonListener() { + @Override + public void onVisibilityChanged(ContextualButton button, boolean visible) { + if (visibilityChangedCallback != null) { + visibilityChangedCallback.accept(visible); + } + } + }); + } + + @Override public void setVisibility(int visibility) { super.setVisibility(visibility); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index eb626280b494..c8fb4e3372c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -179,7 +179,6 @@ import com.android.systemui.statusbar.AutoHideUiElement; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; -import com.android.systemui.statusbar.EmptyShadeView; import com.android.systemui.statusbar.GestureRecorder; import com.android.systemui.statusbar.KeyboardShortcuts; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -189,7 +188,7 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShadeDepthController; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.ScrimView; @@ -1029,7 +1028,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarStateController); mWakeUpCoordinator.setIconAreaController(mNotificationIconAreaController); inflateShelf(); - mNotificationIconAreaController.setupShelf(mNotificationShelf); + mNotificationIconAreaController.setupShelf(mNotificationShelfController); mNotificationPanelViewController.setOnReinflationListener( mNotificationIconAreaController::initAodIcons); mNotificationPanelViewController.addExpansionListener(mWakeUpCoordinator); @@ -1147,7 +1146,8 @@ public class StatusBar extends SystemUI implements DemoMode, }); mScrimController.attachViews(scrimBehind, scrimInFront, scrimForBubble); - mNotificationPanelViewController.initDependencies(this, mGroupManager, mNotificationShelf, + mNotificationPanelViewController.initDependencies(this, mGroupManager, + mNotificationShelfController, mNotificationIconAreaController, mScrimController); BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop); @@ -1310,7 +1310,7 @@ public class StatusBar extends SystemUI implements DemoMode, this /* statusBar */, mShadeController, mCommandQueue, mInitController, mNotificationInterruptStateProvider); - mNotificationShelf.setOnActivatedListener(mPresenter); + mNotificationShelfController.setOnActivatedListener(mPresenter); mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController); mNotificationActivityStarter = @@ -1386,8 +1386,9 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateShelf() { - mNotificationShelf = mSuperStatusBarViewFactory.getNotificationShelf(mStackScroller); - mNotificationShelf.setOnClickListener(mGoToLockedShadeListener); + mNotificationShelfController = mSuperStatusBarViewFactory + .getNotificationShelfController(mStackScroller); + mNotificationShelfController.setOnClickListener(mGoToLockedShadeListener); } @Override @@ -4085,8 +4086,7 @@ public class StatusBar extends SystemUI implements DemoMode, private final Optional<Recents> mRecentsOptional; - protected NotificationShelf mNotificationShelf; - protected EmptyShadeView mEmptyShadeView; + protected NotificationShelfController mNotificationShelfController; private final Lazy<AssistManager> mAssistManagerLazy; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java index 87b3956060f3..bbab6253a4d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java @@ -40,5 +40,9 @@ abstract class AudioActivityObserver { mListener = listener; } + abstract void start(); + + abstract void stop(); + abstract Set<String> getActivePackages(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java index 8e4e12358836..e3eed35f0483 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java @@ -22,12 +22,12 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; import android.annotation.IntDef; import android.annotation.UiThread; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.graphics.PixelFormat; import android.provider.Settings; import android.text.TextUtils; @@ -65,11 +65,13 @@ public class AudioRecordingDisclosureBar implements // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator"; + private static final String ENABLE_FLAG = "sysui_mic_disclosure_enable"; private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt"; private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced"; @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"STATE_"}, value = { + STATE_STOPPED, STATE_NOT_SHOWN, STATE_APPEARING, STATE_SHOWN, @@ -80,6 +82,7 @@ public class AudioRecordingDisclosureBar implements }) public @interface State {} + private static final int STATE_STOPPED = -1; private static final int STATE_NOT_SHOWN = 0; private static final int STATE_APPEARING = 1; private static final int STATE_SHOWN = 2; @@ -90,10 +93,9 @@ public class AudioRecordingDisclosureBar implements private static final int ANIMATION_DURATION = 600; private static final int MAXIMIZED_DURATION = 3000; - private static final int PULSE_BIT_DURATION = 1000; - private static final float PULSE_SCALE = 1.25f; private final Context mContext; + private boolean mIsEnabledInSettings; private View mIndicatorView; private View mIconTextsContainer; @@ -104,13 +106,13 @@ public class AudioRecordingDisclosureBar implements private TextView mTextView; private boolean mIsLtr; - @State private int mState = STATE_NOT_SHOWN; + @State private int mState = STATE_STOPPED; /** * Array of the observers that monitor different aspects of the system, such as AppOps and * microphone foreground services */ - private final AudioActivityObserver[] mAudioActivityObservers; + private AudioActivityObserver[] mAudioActivityObservers; /** * Whether the indicator should expand and show the recording application's label. * If disabled ({@code false}) the "minimized" ({@link #STATE_MINIMIZED}) indicator would appear @@ -144,6 +146,7 @@ public class AudioRecordingDisclosureBar implements public AudioRecordingDisclosureBar(Context context) { mContext = context; + // Loading configs mRevealRecordingPackages = mContext.getResources().getBoolean( R.bool.audio_recording_disclosure_reveal_packages); mExemptPackages = new ArraySet<>( @@ -152,10 +155,52 @@ public class AudioRecordingDisclosureBar implements mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST))); mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST))); - mAudioActivityObservers = new AudioActivityObserver[]{ - new RecordAudioAppOpObserver(mContext, this), - new MicrophoneForegroundServicesObserver(mContext, this), - }; + // Check setting, and start if enabled + mIsEnabledInSettings = checkIfEnabledInSettings(); + registerSettingsObserver(); + if (mIsEnabledInSettings) { + start(); + } + } + + @UiThread + private void start() { + if (mState != STATE_STOPPED) { + return; + } + mState = STATE_NOT_SHOWN; + + if (mAudioActivityObservers == null) { + mAudioActivityObservers = new AudioActivityObserver[]{ + new RecordAudioAppOpObserver(mContext, this), + new MicrophoneForegroundServicesObserver(mContext, this), + }; + } + + for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) { + mAudioActivityObservers[i].start(); + } + } + + @UiThread + private void stop() { + if (mState == STATE_STOPPED) { + return; + } + mState = STATE_STOPPED; + + for (int i = mAudioActivityObservers.length - 1; i >= 0; i--) { + mAudioActivityObservers[i].stop(); + } + + // Remove the view if shown. + if (mState != STATE_NOT_SHOWN) { + removeIndicatorView(); + } + + // Clean up the state. + mSessionNotifiedPackages.clear(); + mPendingNotificationPackages.clear(); } @UiThread @@ -213,7 +258,6 @@ public class AudioRecordingDisclosureBar implements @UiThread private void hideIndicatorIfNeeded() { - if (DEBUG) Log.d(TAG, "hideIndicatorIfNeeded"); // If not MINIMIZED, will check whether the indicator should be hidden when the indicator // comes to the STATE_MINIMIZED eventually. if (mState != STATE_MINIMIZED) return; @@ -222,7 +266,6 @@ public class AudioRecordingDisclosureBar implements for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) { for (String activePackage : mAudioActivityObservers[index].getActivePackages()) { if (mExemptPackages.contains(activePackage)) continue; - if (DEBUG) Log.d(TAG, " - there are still ongoing activities"); return; } } @@ -235,7 +278,7 @@ public class AudioRecordingDisclosureBar implements @UiThread private void show(String packageName) { if (DEBUG) { - Log.d(TAG, "Showing indicator for " + packageName); + Log.d(TAG, "Showing indicator"); } mIsLtr = mContext.getResources().getConfiguration().getLayoutDirection() @@ -286,6 +329,10 @@ public class AudioRecordingDisclosureBar implements new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { + if (mState == STATE_STOPPED) { + return; + } + // Remove the observer mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener( this); @@ -306,13 +353,16 @@ public class AudioRecordingDisclosureBar implements @Override public void onAnimationStart(Animator animation, boolean isReverse) { + if (mState == STATE_STOPPED) { + return; + } + // Indicator is INVISIBLE at the moment, change it. mIndicatorView.setVisibility(View.VISIBLE); } @Override public void onAnimationEnd(Animator animation) { - startPulsatingAnimation(); if (mRevealRecordingPackages) { onExpanded(); } else { @@ -345,9 +395,6 @@ public class AudioRecordingDisclosureBar implements assertRevealingRecordingPackages(); final String label = getApplicationLabel(packageName); - if (DEBUG) { - Log.d(TAG, "Expanding for " + packageName + " (" + label + ")..."); - } mTextView.setText(mContext.getString(R.string.app_accessed_mic, label)); final AnimatorSet set = new AnimatorSet(); @@ -373,7 +420,6 @@ public class AudioRecordingDisclosureBar implements private void minimize() { assertRevealingRecordingPackages(); - if (DEBUG) Log.d(TAG, "Minimizing..."); final int targetOffset = (mIsLtr ? 1 : -1) * mTextsContainers.getWidth(); final AnimatorSet set = new AnimatorSet(); set.playTogether( @@ -396,7 +442,9 @@ public class AudioRecordingDisclosureBar implements @UiThread private void hide() { - if (DEBUG) Log.d(TAG, "Hiding..."); + if (DEBUG) { + Log.d(TAG, "Hide indicator"); + } final int targetOffset = (mIsLtr ? 1 : -1) * (mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX()); final AnimatorSet set = new AnimatorSet(); @@ -418,9 +466,12 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onExpanded() { + if (mState == STATE_STOPPED) { + return; + } + assertRevealingRecordingPackages(); - if (DEBUG) Log.d(TAG, "Expanded"); mState = STATE_SHOWN; mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION); @@ -428,7 +479,10 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onMinimized() { - if (DEBUG) Log.d(TAG, "Minimized"); + if (mState == STATE_STOPPED) { + return; + } + mState = STATE_MINIMIZED; if (mRevealRecordingPackages) { @@ -443,8 +497,21 @@ public class AudioRecordingDisclosureBar implements @UiThread private void onHidden() { - if (DEBUG) Log.d(TAG, "Hidden"); + if (mState == STATE_STOPPED) { + return; + } + removeIndicatorView(); + mState = STATE_NOT_SHOWN; + + // Check if anybody started recording while we were in STATE_DISAPPEARING + if (!mPendingNotificationPackages.isEmpty()) { + // There is a new application that started recording, tell the user about it. + show(mPendingNotificationPackages.poll()); + } + } + + private void removeIndicatorView() { final WindowManager windowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); windowManager.removeView(mIndicatorView); @@ -456,28 +523,6 @@ public class AudioRecordingDisclosureBar implements mTextsContainers = null; mTextView = null; mBgEnd = null; - - mState = STATE_NOT_SHOWN; - - // Check if anybody started recording while we were in STATE_DISAPPEARING - if (!mPendingNotificationPackages.isEmpty()) { - // There is a new application that started recording, tell the user about it. - show(mPendingNotificationPackages.poll()); - } - } - - @UiThread - private void startPulsatingAnimation() { - final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle); - final ObjectAnimator animator = - ObjectAnimator.ofPropertyValuesHolder( - pulsatingView, - PropertyValuesHolder.ofFloat(View.SCALE_X, PULSE_SCALE), - PropertyValuesHolder.ofFloat(View.SCALE_Y, PULSE_SCALE)); - animator.setDuration(PULSE_BIT_DURATION); - animator.setRepeatCount(ObjectAnimator.INFINITE); - animator.setRepeatMode(ObjectAnimator.REVERSE); - animator.start(); } private String[] getGlobalStringArray(String setting) { @@ -504,4 +549,33 @@ public class AudioRecordingDisclosureBar implements DEBUG ? new RuntimeException("Should not be called") : null); } } + + private boolean checkIfEnabledInSettings() { + // 0 = disabled, everything else = enabled. Enabled by default. + return Settings.Global.getInt(mContext.getContentResolver(), + ENABLE_FLAG, 1) != 0; + } + + private void registerSettingsObserver() { + final ContentObserver contentObserver = new ContentObserver( + mContext.getMainThreadHandler()) { + @Override + public void onChange(boolean selfChange) { + if (mIsEnabledInSettings == checkIfEnabledInSettings()) { + // Nothing changed as we know it - ignore. + return; + } + + // Things changed: flip the flag. + mIsEnabledInSettings = !mIsEnabledInSettings; + if (mIsEnabledInSettings) { + start(); + } else { + stop(); + } + } + }; + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(ENABLE_FLAG), false, contentObserver); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java index 1ede88a26020..8caf95fb48f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java @@ -30,7 +30,6 @@ import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,9 +40,8 @@ import java.util.Set; */ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { private static final String TAG = "MicrophoneForegroundServicesObserver"; - private static final boolean ENABLED = true; - private final IActivityManager mActivityManager; + private IActivityManager mActivityManager; /** * A dictionary that maps PIDs to the package names. We only keep track of the PIDs that are * "active" (those that are running FGS with FOREGROUND_SERVICE_TYPE_MICROPHONE flag). @@ -60,7 +58,10 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { MicrophoneForegroundServicesObserver(Context context, OnAudioActivityStateChangeListener listener) { super(context, listener); + } + @Override + void start() { mActivityManager = ActivityManager.getService(); try { mActivityManager.registerProcessObserver(mProcessObserver); @@ -70,8 +71,19 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { } @Override + void stop() { + try { + mActivityManager.unregisterProcessObserver(mProcessObserver); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't unregister process observer", e); + } + mActivityManager = null; + mPackageToProcessCount.clear(); + } + + @Override Set<String> getActivePackages() { - return ENABLED ? mPackageToProcessCount.keySet() : Collections.emptySet(); + return mPackageToProcessCount.keySet(); } @UiThread @@ -141,13 +153,12 @@ class MicrophoneForegroundServicesObserver extends AudioActivityObserver { @UiThread private void notifyPackageStateChanged(String packageName, boolean active) { - if (active) { - if (DEBUG) Log.d(TAG, "New microphone fgs detected, package=" + packageName); - } else { - if (DEBUG) Log.d(TAG, "Microphone fgs is gone, package=" + packageName); + if (DEBUG) { + Log.d(TAG, (active ? "New microphone fgs detected" : "Microphone fgs is gone") + + ", package=" + packageName); } - if (ENABLED) mListener.onAudioActivityStateChange(active, packageName); + mListener.onAudioActivityStateChange(active, packageName); } @UiThread diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java index b5b1c2b3018a..9a2b4a93ac89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java @@ -42,14 +42,33 @@ class RecordAudioAppOpObserver extends AudioActivityObserver implements RecordAudioAppOpObserver(Context context, OnAudioActivityStateChangeListener listener) { super(context, listener); + } + + @Override + void start() { + if (DEBUG) { + Log.d(TAG, "Start"); + } // Register AppOpsManager callback - final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService( - Context.APP_OPS_SERVICE); - appOpsManager.startWatchingActive( - new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, - mContext.getMainExecutor(), - this); + mContext.getSystemService(AppOpsManager.class) + .startWatchingActive( + new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, + mContext.getMainExecutor(), + this); + } + + @Override + void stop() { + if (DEBUG) { + Log.d(TAG, "Stop"); + } + + // Unregister AppOpsManager callback + mContext.getSystemService(AppOpsManager.class).stopWatchingActive(this); + + // Clean up state + mActiveAudioRecordingPackages.clear(); } @UiThread diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index 551b7b41212a..d16bedcad960 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -23,6 +23,7 @@ import android.view.InflateException; import android.view.LayoutInflater; import android.view.View; +import com.android.keyguard.KeyguardClockSwitch; import com.android.keyguard.KeyguardMessageArea; import com.android.keyguard.KeyguardSliceView; import com.android.systemui.dagger.SystemUIRootComponent; @@ -126,11 +127,6 @@ public class InjectionInflationController { NotificationStackScrollLayout createNotificationStackScrollLayout(); /** - * Creates the Shelf. - */ - NotificationShelf creatNotificationShelf(); - - /** * Creates the KeyguardSliceView. */ KeyguardSliceView createKeyguardSliceView(); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 3455ff47de8d..4b119dd7e176 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -150,6 +150,8 @@ public class VolumeDialogImpl implements VolumeDialog, private boolean mShowing; private boolean mShowA11yStream; + private final boolean mShowLowMediaVolumeIcon; + private int mActiveStream; private int mPrevActiveStream; private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE; @@ -166,7 +168,7 @@ public class VolumeDialogImpl implements VolumeDialog, public VolumeDialogImpl(Context context) { mContext = - new ContextThemeWrapper(context, R.style.qs_theme); + new ContextThemeWrapper(context, R.style.volume_dialog_theme); mController = Dependency.get(VolumeDialogController.class); mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); @@ -175,6 +177,8 @@ public class VolumeDialogImpl implements VolumeDialog, mShowActiveStreamOnly = showActiveStreamOnly(); mHasSeenODICaptionsTooltip = Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); + mShowLowMediaVolumeIcon = + mContext.getResources().getBoolean(R.bool.config_showLowMediaVolumeIcon); } @Override @@ -421,6 +425,7 @@ public class VolumeDialogImpl implements VolumeDialog, row.dndIcon = row.view.findViewById(R.id.dnd_icon); row.slider = row.view.findViewById(R.id.volume_row_slider); row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row)); + row.number = row.view.findViewById(R.id.volume_number); row.anim = null; @@ -1024,19 +1029,28 @@ public class VolumeDialogImpl implements VolumeDialog, final boolean iconEnabled = (mAutomute || ss.muteSupported) && !zenMuted; row.icon.setEnabled(iconEnabled); row.icon.setAlpha(iconEnabled ? 1 : 0.5f); - final int iconRes = - isRingVibrate ? R.drawable.ic_volume_ringer_vibrate - : isRingSilent || zenMuted ? row.iconMuteRes - : ss.routedToBluetooth - ? isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute - : R.drawable.ic_volume_media_bt - : isStreamMuted(ss) ? row.iconMuteRes : row.iconRes; + final int iconRes; + if (isRingVibrate) { + iconRes = R.drawable.ic_volume_ringer_vibrate; + } else if (isRingSilent || zenMuted) { + iconRes = row.iconMuteRes; + } else if (ss.routedToBluetooth) { + iconRes = isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute + : R.drawable.ic_volume_media_bt; + } else if (isStreamMuted(ss)) { + iconRes = row.iconMuteRes; + } else { + iconRes = mShowLowMediaVolumeIcon && ss.level * 2 < (ss.levelMax + ss.levelMin) + ? R.drawable.ic_volume_media_low : row.iconRes; + } + row.icon.setImageResource(iconRes); row.iconState = iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes) ? Events.ICON_STATE_MUTE - : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes) + : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes + || iconRes == R.drawable.ic_volume_media_low) ? Events.ICON_STATE_UNMUTE : Events.ICON_STATE_UNKNOWN; if (iconEnabled) { @@ -1090,6 +1104,7 @@ public class VolumeDialogImpl implements VolumeDialog, final int vlevel = row.ss.muted && (!isRingStream && !zenMuted) ? 0 : row.ss.level; updateVolumeRowSliderH(row, enableSlider, vlevel); + if (row.number != null) row.number.setText(Integer.toString(vlevel)); } private boolean isStreamMuted(final StreamState streamState) { @@ -1115,6 +1130,10 @@ public class VolumeDialogImpl implements VolumeDialog, row.icon.setImageTintList(tint); row.icon.setImageAlpha(alpha); row.cachedTint = tint; + if (row.number != null) { + row.number.setTextColor(tint); + row.number.setAlpha(alpha); + } } private void updateVolumeRowSliderH(VolumeRow row, boolean enable, int vlevel) { @@ -1346,7 +1365,7 @@ public class VolumeDialogImpl implements VolumeDialog, private final class CustomDialog extends Dialog implements DialogInterface { public CustomDialog(Context context) { - super(context, R.style.qs_theme); + super(context, R.style.volume_dialog_theme); } @Override @@ -1458,6 +1477,7 @@ public class VolumeDialogImpl implements VolumeDialog, private TextView header; private ImageButton icon; private SeekBar slider; + private TextView number; private int stream; private StreamState ss; private long userAttempt; // last user-driven slider change diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index b7589534a770..1538a32ecf8a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -60,6 +60,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -70,7 +71,9 @@ import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RankingBuilder; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; @@ -79,8 +82,10 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; @@ -90,6 +95,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.InjectionInflationController; import com.google.common.collect.ImmutableList; @@ -174,6 +180,8 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; @Mock + private NotificationShelfComponent mNotificationShelfComponent; + @Mock private NotifPipeline mNotifPipeline; @Mock private FeatureFlags mFeatureFlagsOldPipeline; @@ -185,11 +193,14 @@ public class BubbleControllerTest extends SysuiTestCase { private IStatusBarService mStatusBarService; @Mock private LauncherApps mLauncherApps; + @Mock private LockscreenLockIconController mLockIconController; private BubbleData mBubbleData; private TestableLooper mTestableLooper; + private SuperStatusBarViewFactory mSuperStatusBarViewFactory; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -199,6 +210,23 @@ public class BubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new NotificationShelfComponent.Builder() { + @Override + public NotificationShelfComponent.Builder notificationShelf( + NotificationShelf view) { + return this; + } + + @Override + public NotificationShelfComponent build() { + return mNotificationShelfComponent; + } + }, + mLockIconController); + + // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, mConfigurationController, mKeyguardViewMediator, mKeyguardBypassController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 43bf19111049..0e7cb79ec266 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -58,6 +58,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.statusbar.IStatusBarService; +import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -66,7 +67,9 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; +import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.RankingBuilder; +import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; @@ -75,7 +78,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenLockIconController; @@ -88,6 +91,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Ignore; @@ -168,7 +172,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { @Mock private ShadeController mShadeController; @Mock - private NotificationRowComponent mNotificationRowComponent; + private NotificationShelfComponent mNotificationShelfComponent; @Mock private NotifPipeline mNotifPipeline; @Mock @@ -185,6 +189,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { private BubbleData mBubbleData; private TestableLooper mTestableLooper; + private SuperStatusBarViewFactory mSuperStatusBarViewFactory; @Before public void setUp() throws Exception { @@ -195,6 +200,22 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); + mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, + new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), + new NotificationShelfComponent.Builder() { + @Override + public NotificationShelfComponent.Builder notificationShelf( + NotificationShelf view) { + return this; + } + + @Override + public NotificationShelfComponent build() { + return mNotificationShelfComponent; + } + }, + mLockIconController); + // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, 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/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index ddac2ecbd6eb..85701c24f7d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -197,7 +198,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class)); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false); + NotificationShelfController notificationShelfController = + mock(NotificationShelfController.class); NotificationShelf notificationShelf = mock(NotificationShelf.class); + when(notificationShelfController.getView()).thenReturn(notificationShelf); when(mNotificationSectionsManager.createSectionsForBuckets()).thenReturn( new NotificationSection[]{ mNotificationSection @@ -230,7 +234,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture()); mUserChangedListener = userChangedCaptor.getValue(); mStackScroller = spy(mStackScrollerInternal); - mStackScroller.setShelf(notificationShelf); + mStackScroller.setShelfController(notificationShelfController); mStackScroller.setStatusBar(mBar); mStackScroller.setScrimController(mock(ScrimController.class)); mStackScroller.setGroupManager(mGroupManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java index f21235c12cde..f66524114292 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarRotationContextTest.java @@ -60,7 +60,7 @@ public class NavigationBarRotationContextTest extends SysuiTestCase { final View view = new View(mContext); mRotationButton = mock(RotationButton.class); mRotationButtonController = spy(new RotationButtonController(mContext, 0, 0, - mRotationButton)); + mRotationButton, (visibility) -> {})); final KeyButtonDrawable kbd = mock(KeyButtonDrawable.class); doReturn(view).when(mRotationButton).getCurrentView(); doReturn(true).when(mRotationButton).acceptRotationProposal(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index c7434f6fd95f..bf4ccd22effd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -63,7 +63,7 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationShelf; +import com.android.systemui.statusbar.NotificationShelfController; import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -115,7 +115,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { @Mock private HeadsUpManagerPhone mHeadsUpManager; @Mock - private NotificationShelf mNotificationShelf; + private NotificationShelfController mNotificationShelfController; @Mock private NotificationGroupManager mGroupManager; @Mock @@ -246,7 +246,7 @@ public class NotificationPanelViewTest extends SysuiTestCase { mBiometricUnlockController, mStatusBarKeyguardViewManager, () -> mKeyguardClockSwitchController); mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager, - mNotificationShelf, mNotificationAreaController, mScrimController); + mNotificationShelfController, mNotificationAreaController, mScrimController); mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager); mNotificationPanelViewController.setBar(mPanelBar); diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt index 4b6bbac051e0..75c819bb0ced 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt @@ -18,33 +18,40 @@ package com.android.networkstack.tethering import android.app.Notification import android.app.NotificationManager +import android.app.PendingIntent +import android.app.PendingIntent.FLAG_IMMUTABLE import android.content.Context +import android.content.Intent import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.content.res.Resources import android.net.ConnectivityManager.TETHERING_WIFI +import android.net.NetworkCapabilities +import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.Handler import android.os.HandlerThread import android.os.Looper -import android.net.NetworkCapabilities -import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING import android.os.UserHandle +import android.provider.Settings import android.telephony.TelephonyManager import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 import com.android.internal.util.test.BroadcastInterceptingContext +import com.android.networkstack.tethering.TetheringNotificationUpdater.ACTION_DISABLE_TETHERING import com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE import com.android.networkstack.tethering.TetheringNotificationUpdater.EVENT_SHOW_NO_UPSTREAM import com.android.networkstack.tethering.TetheringNotificationUpdater.NO_UPSTREAM_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.RESTRICTED_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.ROAMING_NOTIFICATION_ID import com.android.networkstack.tethering.TetheringNotificationUpdater.VERIZON_CARRIER_ID +import com.android.networkstack.tethering.TetheringNotificationUpdater.getSettingsPackageName import com.android.testutils.waitForIdle import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Assert.fail import org.junit.Before import org.junit.Test @@ -87,12 +94,17 @@ class TetheringNotificationUpdaterTest { // every test but should always be initialized before use (or the test should crash). private lateinit var context: TestContext private lateinit var notificationUpdater: TetheringNotificationUpdater + + // Initializing the following members depends on initializing some of the mocks and + // is more logically done in setup(). private lateinit var fakeTetheringThread: HandlerThread private val ROAMING_CAPABILITIES = NetworkCapabilities() private val HOME_CAPABILITIES = NetworkCapabilities().addCapability(NET_CAPABILITY_NOT_ROAMING) private val NOTIFICATION_ICON_ID = R.drawable.stat_sys_tether_general private val TIMEOUT_MS = 500L + private val ACTIVITY_PENDING_INTENT = 0 + private val BROADCAST_PENDING_INTENT = 1 private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) { override fun createContextAsUser(user: UserHandle, flags: Int) = @@ -146,10 +158,43 @@ class TetheringNotificationUpdaterTest { fakeTetheringThread.quitSafely() } + private fun verifyActivityPendingIntent(intent: Intent, flags: Int) { + // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add + // the flag in creating arguments). If the described PendingIntent does not already exist, + // getActivity() will return null instead of PendingIntent object. + val pi = PendingIntent.getActivity( + context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + intent, + flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE, + null /* options */) + assertNotNull("Activity PendingIntent with FLAG_IMMUTABLE does not exist.", pi) + } + + private fun verifyBroadcastPendingIntent(intent: Intent, flags: Int) { + // Use FLAG_NO_CREATE to verify whether PendingIntent has FLAG_IMMUTABLE flag(forcefully add + // the flag in creating arguments). If the described PendingIntent does not already exist, + // getBroadcast() will return null instead of PendingIntent object. + val pi = PendingIntent.getBroadcast( + context.createContextAsUser(UserHandle.CURRENT, 0 /* flags */), + 0 /* requestCode */, + intent, + flags or FLAG_IMMUTABLE or PendingIntent.FLAG_NO_CREATE) + assertNotNull("Broadcast PendingIntent with FLAG_IMMUTABLE does not exist.", pi) + } + private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE) private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT) - private fun verifyNotification(iconId: Int, title: String, text: String, id: Int) { + private fun verifyNotification( + iconId: Int, + title: String, + text: String, + id: Int, + intentSenderType: Int, + intent: Intent, + flags: Int + ) { verify(notificationManager, never()).cancel(any(), eq(id)) val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java) @@ -161,6 +206,11 @@ class TetheringNotificationUpdaterTest { assertEquals(title, notification.title()) assertEquals(text, notification.text()) + when (intentSenderType) { + ACTIVITY_PENDING_INTENT -> verifyActivityPendingIntent(intent, flags) + BROADCAST_PENDING_INTENT -> verifyBroadcastPendingIntent(intent, flags) + } + reset(notificationManager) } @@ -176,6 +226,10 @@ class TetheringNotificationUpdaterTest { @Test fun testRestrictedNotification() { + val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(context.packageManager)) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -183,7 +237,7 @@ class TetheringNotificationUpdaterTest { // User restrictions on. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, - RESTRICTED_NOTIFICATION_ID) + RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // User restrictions off. Clear notification. notificationUpdater.tetheringRestrictionLifted() @@ -196,7 +250,7 @@ class TetheringNotificationUpdaterTest { // User restrictions on again. Show restricted notification. notificationUpdater.notifyTetheringDisabledByRestriction() verifyNotification(NOTIFICATION_ICON_ID, TEST_DISALLOW_TITLE, TEST_DISALLOW_MESSAGE, - RESTRICTED_NOTIFICATION_ID) + RESTRICTED_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) } val MAX_BACKOFF_MS = 200L @@ -234,6 +288,8 @@ class TetheringNotificationUpdaterTest { @Test fun testNoUpstreamNotification() { + val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -246,7 +302,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // Same capabilities changed. Nothing happened. notificationUpdater.onUpstreamCapabilitiesChanged(null) @@ -260,7 +317,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) @@ -305,6 +363,11 @@ class TetheringNotificationUpdaterTest { @Test fun testRoamingNotification() { + val disableIntent = Intent(ACTION_DISABLE_TETHERING).setPackage(context.packageName) + val settingsIntent = Intent(Settings.ACTION_TETHER_SETTINGS) + .setPackage(getSettingsPackageName(context.packageManager)) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + // Set test sub id. notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID) verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID)) @@ -316,7 +379,7 @@ class TetheringNotificationUpdaterTest { // Upstream capabilities changed to roaming state. Show roaming notification. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, - ROAMING_NOTIFICATION_ID) + ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // Same capabilities change. Nothing happened. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) @@ -329,14 +392,15 @@ class TetheringNotificationUpdaterTest { // Upstream capabilities changed to roaming state again. Show roaming notification. notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES) verifyNotification(NOTIFICATION_ICON_ID, TEST_ROAMING_TITLE, TEST_ROAMING_MESSAGE, - ROAMING_NOTIFICATION_ID) + ROAMING_NOTIFICATION_ID, ACTIVITY_PENDING_INTENT, settingsIntent, FLAG_IMMUTABLE) // No upstream. Clear roaming notification and show no upstream notification. notificationUpdater.onUpstreamCapabilitiesChanged(null) notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // No downstream. notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE) @@ -347,7 +411,8 @@ class TetheringNotificationUpdaterTest { notificationUpdater.handler.waitForDelayedMessage(EVENT_SHOW_NO_UPSTREAM, TIMEOUT_MS) verifyNotificationCancelled(listOf(ROAMING_NOTIFICATION_ID), false) verifyNotification(NOTIFICATION_ICON_ID, TEST_NO_UPSTREAM_TITLE, TEST_NO_UPSTREAM_MESSAGE, - NO_UPSTREAM_NOTIFICATION_ID) + NO_UPSTREAM_NOTIFICATION_ID, BROADCAST_PENDING_INTENT, disableIntent, + FLAG_IMMUTABLE) // Set R.bool.config_upstream_roaming_notification to false and change upstream // network to roaming state again. No roaming notification. @@ -363,8 +428,7 @@ class TetheringNotificationUpdaterTest { val testSettingsPackageName = "com.android.test.settings" val pm = mock(PackageManager::class.java) doReturn(null).`when`(pm).resolveActivity(any(), anyInt()) - assertEquals(defaultSettingsPackageName, - TetheringNotificationUpdater.getSettingsPackageName(pm)) + assertEquals(defaultSettingsPackageName, getSettingsPackageName(pm)) val resolveInfo = ResolveInfo().apply { activityInfo = ActivityInfo().apply { @@ -375,7 +439,6 @@ class TetheringNotificationUpdaterTest { } } doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt()) - assertEquals(testSettingsPackageName, - TetheringNotificationUpdater.getSettingsPackageName(pm)) + assertEquals(testSettingsPackageName, getSettingsPackageName(pm)) } } 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 e1baefed4425..c45da8668087 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -609,6 +609,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mSendHoverExitDelayed.cancel(); if (mGestureDetector.isMultiFingerGesturesEnabled() && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (pointerIndex < 0) { + return; + } final float deltaX = mReceivedPointerTracker.getReceivedPointerDownX(pointerId) - rawEvent.getX(pointerIndex); @@ -966,25 +969,32 @@ public class TouchExplorer extends BaseEventStreamTransformation final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); final int secondPtrId = event.getPointerId(1); - float draggingX; - float draggingY; + float draggingX = firstPtrX; + float draggingY = firstPtrY; + if (mDraggingPointerId != INVALID_POINTER_ID) { + // Just use the coordinates of the dragging pointer. + int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (pointerIndex >= 0) { + draggingX = event.getX(pointerIndex); + draggingY = event.getY(pointerIndex); + } else { + // We've lost track of the dragging pointer. Try to recover by invalidating it. + // We'll the drop into the code below to choose a new one. + mDraggingPointerId = INVALID_POINTER_ID; + } + } + // Not quite an else, since the above code can invalidate the pointer 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; + // X and Y initialized to firstPtrX and Y was right 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); } diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java index 1c3116699b2d..a92d334a94fa 100644 --- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java @@ -27,6 +27,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.Drawable; @@ -214,7 +215,13 @@ final class SaveUi { return componentName; } intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL); - return intent.resolveActivity(packageManager); + final ActivityInfo ai = + intent.resolveActivityInfo(packageManager, PackageManager.MATCH_INSTANT); + if (ai != null) { + return new ComponentName(ai.applicationInfo.packageName, ai.name); + } + + return null; } }; final LayoutInflater inflater = LayoutInflater.from(context); diff --git a/services/core/Android.bp b/services/core/Android.bp index e76ec743661c..addaa6568665 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -2,38 +2,25 @@ filegroup { name: "services.core-sources", srcs: ["java/**/*.java"], path: "java", - visibility: ["//frameworks/base/services"], -} - -java_library { - name: "protolog-common", - srcs: [ - "java/com/android/server/protolog/common/**/*.java", - ], - host_supported: true, -} - -java_library { - name: "services.core.wm.protologgroups", - srcs: [ - "java/com/android/server/wm/ProtoLogGroup.java", + visibility: [ + "//frameworks/base/services", + "//frameworks/base/core/java/com/android/internal/protolog", ], - static_libs: ["protolog-common"], } genrule { name: "services.core.protologsrc", srcs: [ - ":services.core.wm.protologgroups", + ":protolog-groups", ":services.core-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + - "--protolog-class com.android.server.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.server.protolog.ProtoLogImpl " + - "--protolog-cache-class 'com.android.server.protolog.ProtoLog$$Cache' " + - "--loggroups-class com.android.server.wm.ProtoLogGroup " + - "--loggroups-jar $(location :services.core.wm.protologgroups) " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + + "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + "--output-srcjar $(out) " + "$(locations :services.core-sources)", out: ["services.core.protolog.srcjar"], @@ -42,14 +29,14 @@ genrule { genrule { name: "generate-protolog.json", srcs: [ - ":services.core.wm.protologgroups", + ":protolog-groups", ":services.core-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) generate-viewer-config " + - "--protolog-class com.android.server.protolog.common.ProtoLog " + - "--loggroups-class com.android.server.wm.ProtoLogGroup " + - "--loggroups-jar $(location :services.core.wm.protologgroups) " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + "--viewer-conf $(out) " + "$(locations :services.core-sources)", out: ["services.core.protolog.json"], @@ -109,6 +96,7 @@ java_library_static { ], static_libs: [ + "protolog-lib", "time_zone_distro", "time_zone_distro_installer", "android.hardware.authsecret-V1.0-java", diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index a3c04be02c6f..c9513592ea79 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -28,7 +28,9 @@ import android.database.ContentObserver; import android.net.Uri; import android.os.BatteryStatsInternal; import android.os.Binder; +import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.ShellCommand; import android.os.SystemProperties; import android.os.UserHandle; import android.provider.Settings; @@ -308,50 +310,134 @@ public class BinderCallsStatsService extends Binder { } boolean verbose = false; + int worksourceUid = Process.INVALID_UID; if (args != null) { - for (final String arg : args) { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; if ("-a".equals(arg)) { verbose = true; - } else if ("--reset".equals(arg)) { + } else if ("-h".equals(arg)) { + pw.println("dumpsys binder_calls_stats options:"); + pw.println(" -a: Verbose"); + pw.println(" --work-source-uid <UID>: Dump binder calls from the UID"); + return; + } else if ("--work-source-uid".equals(arg)) { + i++; + if (i >= args.length) { + throw new IllegalArgumentException( + "Argument expected after \"" + arg + "\""); + } + String uidArg = args[i]; + try { + worksourceUid = Integer.parseInt(uidArg); + } catch (NumberFormatException e) { + pw.println("Invalid UID: " + uidArg); + return; + } + } + } + + if (args.length > 0 && worksourceUid == Process.INVALID_UID) { + // For compatibility, support "cmd"-style commands when passed to "dumpsys". + BinderCallsStatsShellCommand command = new BinderCallsStatsShellCommand(pw); + int status = command.exec(this, null, FileDescriptor.out, FileDescriptor.err, args); + if (status == 0) { + return; + } + } + } + mBinderCallsStats.dump(pw, AppIdToPackageMap.getSnapshot(), worksourceUid, verbose); + } + + @Override + public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out, + ParcelFileDescriptor err, String[] args) { + ShellCommand command = new BinderCallsStatsShellCommand(null); + int status = command.exec(this, in.getFileDescriptor(), out.getFileDescriptor(), + err.getFileDescriptor(), args); + if (status != 0) { + command.onHelp(); + } + return status; + } + + private class BinderCallsStatsShellCommand extends ShellCommand { + private final PrintWriter mPrintWriter; + + BinderCallsStatsShellCommand(PrintWriter printWriter) { + mPrintWriter = printWriter; + } + + @Override + public PrintWriter getOutPrintWriter() { + if (mPrintWriter != null) { + return mPrintWriter; + } + return super.getOutPrintWriter(); + } + + @Override + public int onCommand(String cmd) { + PrintWriter pw = getOutPrintWriter(); + if (cmd == null) { + return -1; + } + + switch (cmd) { + case "--reset": reset(); pw.println("binder_calls_stats reset."); - return; - } else if ("--enable".equals(arg)) { + break; + case "--enable": Binder.setObserver(mBinderCallsStats); - return; - } else if ("--disable".equals(arg)) { + break; + case "--disable": Binder.setObserver(null); - return; - } else if ("--no-sampling".equals(arg)) { + break; + case "--no-sampling": mBinderCallsStats.setSamplingInterval(1); - return; - } else if ("--enable-detailed-tracking".equals(arg)) { + break; + case "--enable-detailed-tracking": SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, "1"); mBinderCallsStats.setDetailedTracking(true); pw.println("Detailed tracking enabled"); - return; - } else if ("--disable-detailed-tracking".equals(arg)) { + break; + case "--disable-detailed-tracking": SystemProperties.set(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, ""); mBinderCallsStats.setDetailedTracking(false); pw.println("Detailed tracking disabled"); - return; - } else if ("--dump-worksource-provider".equals(arg)) { + break; + case "--dump-worksource-provider": + mBinderCallsStats.setDetailedTracking(true); mWorkSourceProvider.dump(pw, AppIdToPackageMap.getSnapshot()); - return; - } else if ("-h".equals(arg)) { - pw.println("binder_calls_stats commands:"); - pw.println(" --reset: Reset stats"); - pw.println(" --enable: Enable tracking binder calls"); - pw.println(" --disable: Disables tracking binder calls"); - pw.println(" --no-sampling: Tracks all calls"); - pw.println(" --enable-detailed-tracking: Enables detailed tracking"); - pw.println(" --disable-detailed-tracking: Disables detailed tracking"); - return; - } else { - pw.println("Unknown option: " + arg); - } + break; + case "--work-source-uid": + String uidArg = getNextArgRequired(); + try { + int uid = Integer.parseInt(uidArg); + mBinderCallsStats.recordAllCallsForWorkSourceUid(uid); + } catch (NumberFormatException e) { + pw.println("Invalid UID: " + uidArg); + return -1; + } + break; + default: + return handleDefaultCommands(cmd); } + return 0; + } + + @Override + public void onHelp() { + PrintWriter pw = getOutPrintWriter(); + pw.println("binder_calls_stats commands:"); + pw.println(" --reset: Reset stats"); + pw.println(" --enable: Enable tracking binder calls"); + pw.println(" --disable: Disables tracking binder calls"); + pw.println(" --no-sampling: Tracks all calls"); + pw.println(" --enable-detailed-tracking: Enables detailed tracking"); + pw.println(" --disable-detailed-tracking: Disables detailed tracking"); + pw.println(" --work-source-uid <UID>: Track all binder calls from the UID"); } - mBinderCallsStats.dump(pw, AppIdToPackageMap.getSnapshot(), verbose); } } 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/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 0ddfa1c16a0a..97f3b373f63e 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -185,10 +185,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub { /** Set of interfaces with active alerts. */ @GuardedBy("mQuotaLock") private HashMap<String, Long> mActiveAlerts = Maps.newHashMap(); - /** Set of UIDs blacklisted on metered networks. */ + /** Set of UIDs denylisted on metered networks. */ @GuardedBy("mRulesLock") private SparseBooleanArray mUidRejectOnMetered = new SparseBooleanArray(); - /** Set of UIDs whitelisted on metered networks. */ + /** Set of UIDs allowlisted on metered networks. */ @GuardedBy("mRulesLock") private SparseBooleanArray mUidAllowOnMetered = new SparseBooleanArray(); /** Set of UIDs with cleartext penalties. */ @@ -561,27 +561,27 @@ public class NetworkManagementService extends INetworkManagementService.Stub { synchronized (mRulesLock) { size = mUidRejectOnMetered.size(); if (size > 0) { - if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered blacklist rules"); + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered denylist rules"); uidRejectOnQuota = mUidRejectOnMetered; mUidRejectOnMetered = new SparseBooleanArray(); } size = mUidAllowOnMetered.size(); if (size > 0) { - if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered whitelist rules"); + if (DBG) Slog.d(TAG, "Pushing " + size + " UIDs to metered allowlist rules"); uidAcceptOnQuota = mUidAllowOnMetered; mUidAllowOnMetered = new SparseBooleanArray(); } } if (uidRejectOnQuota != null) { for (int i = 0; i < uidRejectOnQuota.size(); i++) { - setUidMeteredNetworkBlacklist(uidRejectOnQuota.keyAt(i), + setUidMeteredNetworkDenylist(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i)); } } if (uidAcceptOnQuota != null) { for (int i = 0; i < uidAcceptOnQuota.size(); i++) { - setUidMeteredNetworkWhitelist(uidAcceptOnQuota.keyAt(i), + setUidMeteredNetworkAllowlist(uidAcceptOnQuota.keyAt(i), uidAcceptOnQuota.valueAt(i)); } } @@ -1307,14 +1307,14 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) { + private void setUidOnMeteredNetworkList(int uid, boolean denylist, boolean enable) { NetworkStack.checkNetworkStackPermission(mContext); synchronized (mQuotaLock) { boolean oldEnable; SparseBooleanArray quotaList; synchronized (mRulesLock) { - quotaList = blacklist ? mUidRejectOnMetered : mUidAllowOnMetered; + quotaList = denylist ? mUidRejectOnMetered : mUidAllowOnMetered; oldEnable = quotaList.get(uid, false); } if (oldEnable == enable) { @@ -1324,7 +1324,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth"); try { - if (blacklist) { + if (denylist) { if (enable) { mNetdService.bandwidthAddNaughtyApp(uid); } else { @@ -1353,12 +1353,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } @Override - public void setUidMeteredNetworkBlacklist(int uid, boolean enable) { + public void setUidMeteredNetworkDenylist(int uid, boolean enable) { setUidOnMeteredNetworkList(uid, true, enable); } @Override - public void setUidMeteredNetworkWhitelist(int uid, boolean enable) { + public void setUidMeteredNetworkAllowlist(int uid, boolean enable) { setUidOnMeteredNetworkList(uid, false, enable); } @@ -1626,7 +1626,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } } - // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length. + // Normally, allowlist chains only contain deny rules, so numUids == exemptUids.length. // But the code does not guarantee this in any way, and at least in one case - if we add // a UID rule to the firewall, and then disable the firewall - the chains can contain // the wrong type of rule. In this case, don't close connections that we shouldn't. @@ -1691,7 +1691,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { // Close any sockets that were opened by the affected UIDs. This has to be done after // disabling network connectivity, in case they react to the socket close by reopening // the connection and race with the iptables commands that enable the firewall. All - // whitelist and blacklist chains allow RSTs through. + // allowlist and denylist chains allow RSTs through. if (enable) { closeSocketsForFirewallChainLocked(chain, chainName); } @@ -1828,7 +1828,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } else { ruleName = "deny"; } - } else { // Blacklist mode + } else { // Denylist mode if (rule == FIREWALL_RULE_DENY) { ruleName = "deny"; } else { @@ -1913,8 +1913,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub { pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString()); pw.print("Data saver mode: "); pw.println(mDataSaverMode); synchronized (mRulesLock) { - dumpUidRuleOnQuotaLocked(pw, "blacklist", mUidRejectOnMetered); - dumpUidRuleOnQuotaLocked(pw, "whitelist", mUidAllowOnMetered); + dumpUidRuleOnQuotaLocked(pw, "denylist", mUidRejectOnMetered); + dumpUidRuleOnQuotaLocked(pw, "allowlist", mUidAllowOnMetered); } } @@ -2179,9 +2179,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { } } - void setUidOnMeteredNetworkList(boolean blacklist, int uid, boolean enable) { + void setUidOnMeteredNetworkList(boolean denylist, int uid, boolean enable) { synchronized (mRulesLock) { - if (blacklist) { + if (denylist) { mUidRejectOnMetered.put(uid, enable); } else { mUidAllowOnMetered.put(uid, enable); diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 1689656479a5..e675d8d458c7 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -1453,8 +1453,11 @@ public class PackageWatchdog { } else { mHealthCheckState = HealthCheckState.ACTIVE; } - Slog.i(TAG, "Updated health check state for package " + getName() + ": " - + toString(oldState) + " -> " + toString(mHealthCheckState)); + + if (oldState != mHealthCheckState) { + Slog.i(TAG, "Updated health check state for package " + getName() + ": " + + toString(oldState) + " -> " + toString(mHealthCheckState)); + } return mHealthCheckState; } diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 2534a535079e..59ac09ca2f3d 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -167,7 +167,7 @@ public class VibratorService extends IVibratorService.Stub private boolean mIsVibrating; @GuardedBy("mLock") private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners = - new RemoteCallbackList<>(); + new RemoteCallbackList<>(); private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; @@ -176,16 +176,25 @@ public class VibratorService extends IVibratorService.Stub static native long vibratorInit(); static native long vibratorGetFinalizer(); + static native boolean vibratorExists(long controllerPtr); - static native void vibratorOn(long milliseconds); + + static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration); + static native void vibratorOff(long controllerPtr); + static native void vibratorSetAmplitude(long controllerPtr, int amplitude); + static native int[] vibratorGetSupportedEffects(long controllerPtr); + static native long vibratorPerformEffect(long effect, long strength, Vibration vibration, boolean withCallback); - static native void vibratorPerformComposedEffect( + + static native void vibratorPerformComposedEffect(long controllerPtr, VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration); + static native void vibratorSetExternalControl(long controllerPtr, boolean enabled); + static native long vibratorGetCapabilities(long controllerPtr); static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect, long strength); @@ -231,8 +240,7 @@ public class VibratorService extends IVibratorService.Stub // The actual effect to be played. public VibrationEffect effect; - // The original effect that was requested. This is non-null only when the original effect - // differs from the effect that's being played. Typically these two things differ because + // The original effect that was requested. Typically these two things differ because // the effect was scaled based on the users vibration intensity settings. public VibrationEffect originalEffect; @@ -248,9 +256,13 @@ public class VibratorService extends IVibratorService.Stub this.reason = reason; } + @Override public void binderDied() { synchronized (mLock) { if (this == mCurrentVibration) { + if (DEBUG) { + Slog.d(TAG, "Vibration finished because binder died, cleaning up"); + } doCancelVibrateLocked(); } } @@ -261,6 +273,9 @@ public class VibratorService extends IVibratorService.Stub public void onComplete() { synchronized (mLock) { if (this == mCurrentVibration) { + if (DEBUG) { + Slog.d(TAG, "Vibration finished by callback, cleaning up"); + } doCancelVibrateLocked(); } } @@ -915,7 +930,7 @@ public class VibratorService extends IVibratorService.Stub // Callback for whenever the current vibration has finished played out public void onVibrationFinished() { if (DEBUG) { - Slog.e(TAG, "Vibration finished, cleaning up"); + Slog.d(TAG, "Vibration finished, cleaning up"); } synchronized (mLock) { // Make sure the vibration is really done. This also reports that the vibration is @@ -943,25 +958,22 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationInnerLocked(Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked"); try { + long timeout = 0; mCurrentVibration = vib; if (vib.effect instanceof VibrationEffect.OneShot) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; - doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs); - mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration()); + doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib); + timeout = oneShot.getDuration() * ASYNC_TIMEOUT_MULTIPLIER; } else if (vib.effect instanceof VibrationEffect.Waveform) { // mThread better be null here. doCancelVibrate should always be // called before startNextVibrationLocked or startVibrationLocked. - Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; mThread = new VibrateThread(waveform, vib.uid, vib.attrs); mThread.start(); } else if (vib.effect instanceof VibrationEffect.Prebaked) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); - long timeout = doVibratorPrebakedEffectLocked(vib); - if (timeout > 0) { - mH.postDelayed(mVibrationEndRunnable, timeout); - } + timeout = doVibratorPrebakedEffectLocked(vib); } else if (vib.effect instanceof VibrationEffect.Composed) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); doVibratorComposedEffectLocked(vib); @@ -969,10 +981,16 @@ public class VibratorService extends IVibratorService.Stub // devices which support composition also support the completion callback. If we // ever get a device that supports the former but not the latter, then we have no // real way of knowing how long a given effect should last. - mH.postDelayed(mVibrationEndRunnable, 10000); + timeout = 10_000; } else { Slog.e(TAG, "Unknown vibration type, ignoring"); } + // Post extra runnable to ensure vibration will end even if the HAL or native controller + // never triggers the callback. + // TODO: Move ASYNC_TIMEOUT_MULTIPLIER here once native controller is fully integrated. + if (timeout > 0) { + mH.postDelayed(mVibrationEndRunnable, timeout); + } } finally { Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); } @@ -1062,18 +1080,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; @@ -1095,7 +1113,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 @@ -1265,7 +1283,18 @@ public class VibratorService extends IVibratorService.Stub return mNativeWrapper.vibratorExists(); } + /** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */ + private void doVibratorOn(long millis, int amplitude, Vibration vib) { + doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib); + } + + /** Vibrates without native callback. */ private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) { + doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null); + } + + private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs, + @Nullable Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); try { synchronized (mInputDeviceVibrators) { @@ -1280,13 +1309,14 @@ public class VibratorService extends IVibratorService.Stub final int vibratorCount = mInputDeviceVibrators.size(); if (vibratorCount != 0) { for (int i = 0; i < vibratorCount; i++) { - mInputDeviceVibrators.get(i).vibrate(millis, attrs.getAudioAttributes()); + Vibrator inputDeviceVibrator = mInputDeviceVibrators.get(i); + inputDeviceVibrator.vibrate(millis, attrs.getAudioAttributes()); } } else { // Note: ordering is important here! Many haptic drivers will reset their // amplitude when enabled, so we always have to enable first, then set the // amplitude. - mNativeWrapper.vibratorOn(millis); + mNativeWrapper.vibratorOn(millis, vib); doVibratorSetAmplitude(amplitude); } } @@ -1570,6 +1600,7 @@ public class VibratorService extends IVibratorService.Stub proto.flush(); } + /** Thread that plays a single {@link VibrationEffect.Waveform}. */ private class VibrateThread extends Thread { private final VibrationEffect.Waveform mWaveform; private final int mUid; @@ -1738,8 +1769,8 @@ public class VibratorService extends IVibratorService.Stub } /** Turns vibrator on for given time. */ - public void vibratorOn(long milliseconds) { - VibratorService.vibratorOn(milliseconds); + public void vibratorOn(long milliseconds, @Nullable Vibration vibration) { + VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration); } /** Turns vibrator off. */ @@ -1766,7 +1797,7 @@ public class VibratorService extends IVibratorService.Stub /** Turns vibrator on to perform one of the supported composed effects. */ public void vibratorPerformComposedEffect( VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) { - VibratorService.vibratorPerformComposedEffect(effect, vibration); + VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration); } /** Enabled the device vibrator to be controlled by another service. */ @@ -1865,7 +1896,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" @@ -1873,6 +1904,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 71d12eed5412..b62ff1c26f8f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -14055,13 +14055,13 @@ public class ActivityManagerService extends IActivityManager.Stub public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { - return registerReceiverWithFeature(caller, callerPackage, null, receiver, filter, - permission, userId, flags); + return registerReceiverWithFeature(caller, callerPackage, null, null, + receiver, filter, permission, userId, flags); } public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, - String callerFeatureId, IIntentReceiver receiver, IntentFilter filter, - String permission, int userId, int flags) { + String callerFeatureId, String receiverId, IIntentReceiver receiver, + IntentFilter filter, String permission, int userId, int flags) { enforceNotIsolatedCaller("registerReceiver"); ArrayList<Intent> stickyIntents = null; ProcessRecord callerApp = null; @@ -14198,7 +14198,7 @@ public class ActivityManagerService extends IActivityManager.Stub + " callerPackage is " + callerPackage); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId, - permission, callingUid, userId, instantApp, visibleToInstantApps); + receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps); if (rl.containsFilter(filter)) { Slog.w(TAG, "Receiver with filter " + filter + " already registered for pid " + rl.pid diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 578db6f9dba1..50e06c30e17d 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -28,6 +28,7 @@ final class BroadcastFilter extends IntentFilter { final ReceiverList receiverList; final String packageName; final String featureId; + final String receiverId; final String requiredPermission; final int owningUid; final int owningUserId; @@ -35,12 +36,13 @@ final class BroadcastFilter extends IntentFilter { final boolean visibleToInstantApp; BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, - String _packageName, String _featureId, String _requiredPermission, int _owningUid, int _userId, - boolean _instantApp, boolean _visibleToInstantApp) { + String _packageName, String _featureId, String _receiverId, String _requiredPermission, + int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp) { super(_filter); receiverList = _receiverList; packageName = _packageName; featureId = _featureId; + receiverId = _receiverId; requiredPermission = _requiredPermission; owningUid = _owningUid; owningUserId = _userId; diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 12937b988beb..960d26b5da34 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -639,7 +639,7 @@ public final class BroadcastQueue { final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission); if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid, - r.callerPackage, r.callerFeatureId, "") + r.callerPackage, r.callerFeatureId, "Broadcast sent to protected receiver") != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: broadcasting " + r.intent.toString() @@ -672,7 +672,8 @@ public final class BroadcastQueue { int appOp = AppOpsManager.permissionToOpCode(requiredPermission); if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp && mService.getAppOpsManager().noteOpNoThrow(appOp, - filter.receiverList.uid, filter.packageName, filter.featureId, "") + filter.receiverList.uid, filter.packageName, filter.featureId, + "Broadcast delivered to registered receiver " + filter.receiverId) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent.toString() @@ -704,7 +705,8 @@ public final class BroadcastQueue { } if (!skip && r.appOp != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(r.appOp, - filter.receiverList.uid, filter.packageName, filter.featureId, "") + filter.receiverList.uid, filter.packageName, filter.featureId, + "Broadcast delivered to registered receiver " + filter.receiverId) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent.toString() @@ -1366,9 +1368,10 @@ public final class BroadcastQueue { skip = true; } else if (!skip && info.activityInfo.permission != null) { final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); - if (opCode != AppOpsManager.OP_NONE - && mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid, r.callerPackage, - r.callerFeatureId, "") != AppOpsManager.MODE_ALLOWED) { + if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode, + r.callingUid, r.callerPackage, r.callerFeatureId, + "Broadcast delivered to " + info.activityInfo.name) + != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" @@ -1407,7 +1410,8 @@ public final class BroadcastQueue { if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp && mService.getAppOpsManager().noteOpNoThrow(appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, - null /* default featureId */, "") + null /* default featureId */, + "Broadcast delivered to " + info.activityInfo.name) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent + " to " @@ -1424,7 +1428,7 @@ public final class BroadcastQueue { if (!skip && r.appOp != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(r.appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, - null /* default featureId */, "") + null /* default featureId */, "Broadcast delivered to " + info.activityInfo.name) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent + " to " diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 366f30318cd5..b94396634530 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1282,7 +1282,6 @@ public class AudioService extends IAudioService.Stub } if (isPlatformTelevision()) { - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { updateHdmiCecSinkLocked(mHdmiCecSink | false); @@ -1302,22 +1301,54 @@ public class AudioService extends IAudioService.Stub } } - private void checkAddAllFixedVolumeDevices(int device, String caller) { + /** + * Update volume states for the given device. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param caller caller of this method + */ + private void updateVolumeStatesForAudioDevice(int device, String caller) { final int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (!mStreamStates[streamType].hasIndexForDevice(device)) { - // set the default value, if device is affected by a full/fix/abs volume rule, it - // will taken into account in checkFixedVolumeDevices() - mStreamStates[streamType].setIndex( - mStreamStates[mStreamVolumeAlias[streamType]] - .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), - device, caller, true /*hasModifyAudioSettings*/); - } - mStreamStates[streamType].checkFixedVolumeDevices(); + updateVolumeStates(device, streamType, caller); + } + } - // Unmute streams if device is full volume - if (mFullVolumeDevices.contains(device)) { - mStreamStates[streamType].mute(false); + /** + * Update volume states for the given device and given stream. + * + * This will initialize the volume index if no volume index is available. + * If the device is the currently routed device, fixed/full volume policies will be applied. + * + * @param device a single audio device, ensure that this is not a devices bitmask + * @param streamType streamType to be updated + * @param caller caller of this method + */ + private void updateVolumeStates(int device, int streamType, String caller) { + if (!mStreamStates[streamType].hasIndexForDevice(device)) { + // set the default value, if device is affected by a full/fix/abs volume rule, it + // will taken into account in checkFixedVolumeDevices() + mStreamStates[streamType].setIndex( + mStreamStates[mStreamVolumeAlias[streamType]] + .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), + device, caller, true /*hasModifyAudioSettings*/); + } + + // Check if device to be updated is routed for the given audio stream + List<AudioDeviceAttributes> devicesForAttributes = getDevicesForAttributes( + new AudioAttributes.Builder().setInternalLegacyStreamType(streamType).build()); + for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) { + if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType( + device)) { + mStreamStates[streamType].checkFixedVolumeDevices(); + + // Unmute streams if required if device is full volume + if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) { + mStreamStates[streamType].mute(false); + } } } } @@ -4901,7 +4932,15 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { for (int stream = 0; stream < mStreamStates.length; stream++) { if (stream != skipStream) { - mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/); + int devices = mStreamStates[stream].observeDevicesForStream_syncVSS( + false /*checkOthers*/); + + Set<Integer> devicesSet = AudioSystem.generateAudioDeviceTypesSet(devices); + for (Integer device : devicesSet) { + // Update volume states for devices routed for the stream + updateVolumeStates(device, stream, + "AudioService#observeDevicesForStreams"); + } } } } @@ -4970,7 +5009,7 @@ public class AudioService extends IAudioService.Stub + Integer.toHexString(audioSystemDeviceOut) + " from:" + caller)); // make sure we have a volume entry for this device, and that volume is updated according // to volume behavior - checkAddAllFixedVolumeDevices(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); + updateVolumeStatesForAudioDevice(audioSystemDeviceOut, "setDeviceVolumeBehavior:" + caller); } /** @@ -7192,10 +7231,9 @@ public class AudioService extends IAudioService.Stub // HDMI output removeAudioSystemDeviceOutFromFullVolumeDevices(AudioSystem.DEVICE_OUT_HDMI); } + updateVolumeStatesForAudioDevice(AudioSystem.DEVICE_OUT_HDMI, + "HdmiPlaybackClient.DisplayStatusCallback"); } - - checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, - "HdmiPlaybackClient.DisplayStatusCallback"); } private class MyHdmiControlStatusChangeListenerCallback @@ -7903,9 +7941,6 @@ public class AudioService extends IAudioService.Stub return null; } - mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for " - + pcb.asBinder() + " with config:" + policyConfig)).printLog(TAG)); - String regId = null; synchronized (mAudioPolicies) { if (mAudioPolicies.containsKey(pcb.asBinder())) { @@ -7916,6 +7951,13 @@ public class AudioService extends IAudioService.Stub AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener, isFocusPolicy, isTestFocusPolicy, isVolumeController, projection); pcb.asBinder().linkToDeath(app, 0/*flags*/); + + // logging after registration so we have the registration id + mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for " + + pcb.asBinder() + " u/pid:" + Binder.getCallingUid() + "/" + + Binder.getCallingPid() + " with config:" + app.toCompactLogString())) + .printLog(TAG)); + regId = app.getRegistrationId(); mAudioPolicies.put(pcb.asBinder(), app); } catch (RemoteException e) { @@ -8079,7 +8121,10 @@ public class AudioService extends IAudioService.Stub * @param pcb nullable because on service interface */ public void unregisterAudioPolicyAsync(@Nullable IAudioPolicyCallback pcb) { - unregisterAudioPolicy(pcb); + if (pcb == null) { + return; + } + unregisterAudioPolicyInt(pcb, "unregisterAudioPolicyAsync"); } /** @@ -8090,12 +8135,12 @@ public class AudioService extends IAudioService.Stub if (pcb == null) { return; } - unregisterAudioPolicyInt(pcb); + unregisterAudioPolicyInt(pcb, "unregisterAudioPolicy"); } - private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb) { - mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for " + private void unregisterAudioPolicyInt(@NonNull IAudioPolicyCallback pcb, String operationName) { + mDynPolicyLogger.log((new AudioEventLogger.StringEvent(operationName + " for " + pcb.asBinder()).printLog(TAG))); synchronized (mAudioPolicies) { AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder()); @@ -8570,7 +8615,8 @@ public class AudioService extends IAudioService.Stub } public void binderDied() { - Log.i(TAG, "audio policy " + mPolicyCallback + " died"); + mDynPolicyLogger.log((new AudioEventLogger.StringEvent("AudioPolicy " + + mPolicyCallback.asBinder() + " died").printLog(TAG))); release(); } 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..dab8c7fc9d48 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -30,8 +30,6 @@ import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUST import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL; -import static android.view.Surface.ROTATION_270; -import static android.view.Surface.ROTATION_90; import android.Manifest; import android.annotation.NonNull; @@ -46,7 +44,6 @@ import android.content.res.TypedArray; import android.database.ContentObserver; import android.graphics.ColorSpace; import android.graphics.Point; -import android.graphics.Rect; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; @@ -104,7 +101,6 @@ import com.android.server.AnimationThread; import com.android.server.DisplayThread; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; import com.android.server.UiThread; import com.android.server.wm.SurfaceAnimationThread; import com.android.server.wm.WindowManagerInternal; @@ -1394,9 +1390,13 @@ public final class DisplayManagerService extends SystemService { } final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked(); - return SurfaceControl.screenshotToBufferWithSecureLayersUnsafe(token, new Rect(), - displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight(), - false /* useIdentityTransform */, 0 /* rotation */); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(token) + .setSize(displayInfo.getNaturalWidth(), displayInfo.getNaturalHeight()) + .setUseIdentityTransform(true) + .setCaptureSecureLayers(true) + .build(); + return SurfaceControl.captureDisplay(captureArgs); } } @@ -1406,30 +1406,11 @@ public final class DisplayManagerService extends SystemService { if (token == null) { return null; } - final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId); - if (logicalDisplay == null) { - return null; - } - final DisplayInfo displayInfo = logicalDisplay.getDisplayInfoLocked(); - // Takes screenshot based on current device orientation. - final Display display = DisplayManagerGlobal.getInstance() - .getRealDisplay(displayId); - if (display == null) { - return null; - } - final Point displaySize = new Point(); - display.getRealSize(displaySize); - - int rotation = displayInfo.rotation; - // TODO (b/153382624) : This workaround solution would be removed after - // SurfaceFlinger fixes the inconsistency with rotation direction issue. - if (rotation == ROTATION_90 || rotation == ROTATION_270) { - rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90; - } - - return SurfaceControl.screenshotToBuffer(token, new Rect(), displaySize.x, - displaySize.y, false /* useIdentityTransform */, rotation /* rotation */); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(token) + .build(); + return SurfaceControl.captureDisplay(captureArgs); } } @@ -2550,8 +2531,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 +2659,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/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/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java index d4f8c7e855b9..c3532a84c42d 100644 --- a/services/core/java/com/android/server/location/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/LocationProviderManager.java @@ -1615,7 +1615,7 @@ class LocationProviderManager extends case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF: // fall through case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: - updateService(); + updateRegistrations(registration -> true); break; default: break; diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index 8004ec70aaf3..850cf7f4b7ce 100644 --- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -49,8 +49,6 @@ import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; -import android.os.PowerManager.ServiceType; -import android.os.PowerSaveState; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -486,10 +484,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements deviceIdleService.unregisterStationaryListener( mDeviceIdleStationaryListener); } - // Intentional fall-through. - case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED: - case Intent.ACTION_SCREEN_OFF: - case Intent.ACTION_SCREEN_ON: // Call updateLowPowerMode on handler thread so it's always called from the // same thread. mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE); @@ -554,15 +548,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements private void updateLowPowerMode() { // Disable GPS if we are in device idle mode and the device is stationary. boolean disableGpsForPowerManager = mPowerManager.isDeviceIdleMode() && mIsDeviceStationary; - final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.LOCATION); - switch (result.locationMode) { - case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: - case PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: - // If we are in battery saver mode and the screen is off, disable GPS. - disableGpsForPowerManager |= - result.batterySaverEnabled && !mPowerManager.isInteractive(); - break; - } if (disableGpsForPowerManager != mDisableGpsForPowerManager) { mDisableGpsForPowerManager = disableGpsForPowerManager; updateEnabled(); @@ -1959,10 +1944,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ALARM_WAKEUP); intentFilter.addAction(ALARM_TIMEOUT); - intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); - intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f1b89c7a433c..d6e37bacdba8 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -33,6 +33,7 @@ import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HA import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.internal.widget.LockPatternUtils.USER_FRP; +import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_RETURN_GK_PW; import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled; import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential; @@ -186,6 +187,9 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts"; private static final String USER_SERIAL_NUMBER_KEY = "serial-number"; + // TODO (b/145978626) LockSettingsService no longer accepts challenges in the verifyCredential + // paths. These are temporarily left around to ensure that resetLockout works. It will be + // removed once resetLockout is compartmentalized. // No challenge provided private static final int CHALLENGE_NONE = 0; // Challenge was provided from the external caller (non-LockSettingsService) @@ -1308,7 +1312,7 @@ public class LockSettingsService extends ILockSettings.Stub { try { doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle), challengeType, challenge, profileHandle, null /* progressCallback */, - resetLockouts); + resetLockouts, 0 /* flags */); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException @@ -1608,8 +1612,8 @@ public class LockSettingsService extends ILockSettings.Stub { // Verify the parent credential again, to make sure we have a fresh enough // auth token such that getDecryptedPasswordForTiedProfile() inside // setLockCredentialInternal() can function correctly. - verifyCredential(savedCredential, /* challenge */ 0, - mUserManager.getProfileParent(userId).id); + verifyCredential(savedCredential, mUserManager.getProfileParent(userId).id, + 0 /* flags */); savedCredential.zeroize(); savedCredential = LockscreenCredential.createNone(); } @@ -1724,7 +1728,7 @@ public class LockSettingsService extends ILockSettings.Stub { fixateNewestUserKeyAuth(userId); // Refresh the auth token doVerifyCredential(credential, CHALLENGE_FROM_CALLER, 0, userId, - null /* progressCallback */); + null /* progressCallback */, 0 /* flags */); synchronizeUnifiedWorkChallengeForProfiles(userId, null); sendCredentialsOnChangeIfRequired(credential, userId, isLockTiedToParent); return true; @@ -1835,7 +1839,7 @@ public class LockSettingsService extends ILockSettings.Stub { throw new IllegalArgumentException("Non-OK response verifying a credential we just set " + vcr.getResponseCode()); } - byte[] token = vcr.getPayload(); + byte[] token = vcr.getGatekeeperHAT(); if (token == null) { throw new IllegalArgumentException("Empty payload verifying a credential we just set"); } @@ -1968,35 +1972,56 @@ public class LockSettingsService extends ILockSettings.Stub { ICheckCredentialProgressCallback progressCallback) { checkPasswordReadPermission(userId); try { - return doVerifyCredential(credential, CHALLENGE_NONE, 0, userId, progressCallback); + return doVerifyCredential(credential, CHALLENGE_NONE, 0L, userId, progressCallback, + 0 /* flags */); } finally { scheduleGc(); } } @Override + @Nullable public VerifyCredentialResponse verifyCredential(LockscreenCredential credential, - long challenge, int userId) { + int userId, int flags) { checkPasswordReadPermission(userId); - @ChallengeType int challengeType = CHALLENGE_FROM_CALLER; - if (challenge == 0) { - Slog.w(TAG, "VerifyCredential called with challenge=0"); - challengeType = CHALLENGE_NONE; - } try { - return doVerifyCredential(credential, challengeType, challenge, userId, - null /* progressCallback */); + return doVerifyCredential(credential, CHALLENGE_NONE, 0L, userId, + null /* progressCallback */, flags); } finally { scheduleGc(); } } + @Override + public VerifyCredentialResponse verifyGatekeeperPassword(byte[] gatekeeperPassword, + long challenge, int userId) { + checkPasswordReadPermission(userId); + + VerifyCredentialResponse response; + synchronized (mSpManager) { + response = mSpManager.verifyChallengeInternal(getGateKeeperService(), + gatekeeperPassword, challenge, userId); + } + return response; + } + + /** + * @param credential User's lockscreen credential + * @param challengeType Owner of the challenge + * @param challenge Challenge to be wrapped within Gatekeeper's HAT, if the credential is + * verified + * @param userId User to verify the credential for + * @param progressCallback Receive progress callbacks + * @param flags See {@link LockPatternUtils.VerifyFlag} + * @return See {@link VerifyCredentialResponse} + */ private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential, @ChallengeType int challengeType, long challenge, int userId, - ICheckCredentialProgressCallback progressCallback) { + ICheckCredentialProgressCallback progressCallback, + @LockPatternUtils.VerifyFlag int flags) { return doVerifyCredential(credential, challengeType, challenge, userId, - progressCallback, null /* resetLockouts */); + progressCallback, null /* resetLockouts */, flags); } /** @@ -2006,7 +2031,8 @@ public class LockSettingsService extends ILockSettings.Stub { private VerifyCredentialResponse doVerifyCredential(LockscreenCredential credential, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, - @Nullable ArrayList<PendingResetLockout> resetLockouts) { + @Nullable ArrayList<PendingResetLockout> resetLockouts, + @LockPatternUtils.VerifyFlag int flags) { if (credential == null || credential.isNone()) { throw new IllegalArgumentException("Credential can't be null or empty"); } @@ -2017,7 +2043,7 @@ public class LockSettingsService extends ILockSettings.Stub { } VerifyCredentialResponse response = null; response = spBasedDoVerifyCredential(credential, challengeType, challenge, - userId, progressCallback, resetLockouts); + userId, progressCallback, resetLockouts, flags); // The user employs synthetic password based credential. if (response != null) { if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { @@ -2050,7 +2076,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public VerifyCredentialResponse verifyTiedProfileChallenge(LockscreenCredential credential, - long challenge, int userId) { + int userId, @LockPatternUtils.VerifyFlag int flags) { checkPasswordReadPermission(userId); if (!isManagedProfileWithUnifiedLock(userId)) { throw new IllegalArgumentException("User id must be managed profile with unified lock"); @@ -2059,10 +2085,11 @@ public class LockSettingsService extends ILockSettings.Stub { // Unlock parent by using parent's challenge final VerifyCredentialResponse parentResponse = doVerifyCredential( credential, - CHALLENGE_FROM_CALLER, - challenge, + CHALLENGE_NONE, + 0L, parentProfileId, - null /* progressCallback */); + null /* progressCallback */, + flags); if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) { // Failed, just return parent's response return parentResponse; @@ -2071,9 +2098,10 @@ public class LockSettingsService extends ILockSettings.Stub { try { // Unlock work profile, and work profile with unified lock must use password only return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId), - CHALLENGE_FROM_CALLER, - challenge, - userId, null /* progressCallback */); + CHALLENGE_NONE, + 0L, + userId, null /* progressCallback */, + flags); } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | IllegalBlockSizeException @@ -2132,8 +2160,8 @@ public class LockSettingsService extends ILockSettings.Stub { unlockKeystore(credential.getCredential(), userId); Slog.i(TAG, "Unlocking user " + userId + " with token length " - + response.getPayload().length); - unlockUser(userId, response.getPayload(), secretFromCredential(credential)); + + response.getGatekeeperHAT().length); + unlockUser(userId, response.getGatekeeperHAT(), secretFromCredential(credential)); if (isManagedProfileWithSeparatedLock(userId)) { setDeviceUnlockedForUser(userId); @@ -2684,7 +2712,8 @@ public class LockSettingsService extends ILockSettings.Stub { private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential, @ChallengeType int challengeType, long challenge, int userId, ICheckCredentialProgressCallback progressCallback, - @Nullable ArrayList<PendingResetLockout> resetLockouts) { + @Nullable ArrayList<PendingResetLockout> resetLockouts, + @LockPatternUtils.VerifyFlag int flags) { final boolean hasEnrolledBiometrics = mInjector.hasEnrolledBiometrics(userId); @@ -2705,6 +2734,8 @@ public class LockSettingsService extends ILockSettings.Stub { final AuthenticationResult authResult; VerifyCredentialResponse response; + final boolean returnGkPw = (flags & VERIFY_FLAG_RETURN_GK_PW) != 0; + synchronized (mSpManager) { if (!isSyntheticPasswordBasedCredentialLocked(userId)) { return null; @@ -2717,8 +2748,8 @@ public class LockSettingsService extends ILockSettings.Stub { long handle = getSyntheticPasswordHandleLocked(userId); authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( getGateKeeperService(), handle, userCredential, userId, progressCallback); - response = authResult.gkResponse; + // credential has matched if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) { // perform verifyChallenge with synthetic password which generates the real GK auth @@ -2739,7 +2770,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (resetLockouts == null) { resetLockouts = new ArrayList<>(); } - resetLockouts.add(new PendingResetLockout(userId, response.getPayload())); + resetLockouts.add(new PendingResetLockout(userId, response.getGatekeeperHAT())); } onCredentialVerified(authResult.authToken, challengeType, challenge, resetLockouts, @@ -2750,7 +2781,12 @@ public class LockSettingsService extends ILockSettings.Stub { } } - return response; + if (response.isMatched() && returnGkPw) { + return new VerifyCredentialResponse.Builder() + .setGatekeeperPassword(authResult.authToken.deriveGkPassword()).build(); + } else { + return response; + } } private void onCredentialVerified(AuthenticationToken authToken, @@ -3172,7 +3208,8 @@ public class LockSettingsService extends ILockSettings.Stub { if (cred == null) { return false; } - return doVerifyCredential(cred, CHALLENGE_NONE, 0, userId, null /* progressCallback */) + return doVerifyCredential(cred, CHALLENGE_NONE, 0, userId, + null /* progressCallback */, 0 /* flags */) .getResponseCode() == VerifyCredentialResponse.RESPONSE_OK; } } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index d644b1dc6ca0..e31bf3d514ed 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -482,11 +482,12 @@ public class SyntheticPasswordManager { (int status, WeaverReadResponse readResponse) -> { switch (status) { case WeaverReadStatus.OK: - response[0] = new VerifyCredentialResponse( - fromByteArrayList(readResponse.value)); + response[0] = new VerifyCredentialResponse.Builder().setGatekeeperHAT( + fromByteArrayList(readResponse.value)).build(); break; case WeaverReadStatus.THROTTLE: - response[0] = new VerifyCredentialResponse(readResponse.timeout); + response[0] = VerifyCredentialResponse + .fromTimeout(readResponse.timeout); Slog.e(TAG, "weaver read failed (THROTTLE), slot: " + slot); break; case WeaverReadStatus.INCORRECT_KEY: @@ -494,7 +495,8 @@ public class SyntheticPasswordManager { response[0] = VerifyCredentialResponse.ERROR; Slog.e(TAG, "weaver read failed (INCORRECT_KEY), slot: " + slot); } else { - response[0] = new VerifyCredentialResponse(readResponse.timeout); + response[0] = VerifyCredentialResponse + .fromTimeout(readResponse.timeout); Slog.e(TAG, "weaver read failed (INCORRECT_KEY/THROTTLE), slot: " + slot); } @@ -1007,7 +1009,8 @@ public class SyntheticPasswordManager { return result; } sid = GateKeeper.INVALID_SECURE_USER_ID; - applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload()); + applicationId = transformUnderWeaverSecret(pwdToken, + result.gkResponse.getGatekeeperHAT()); } else { byte[] gkPwdToken = passwordTokenToGkInput(pwdToken); GateKeeperResponse response; @@ -1045,7 +1048,7 @@ public class SyntheticPasswordManager { } } } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { - result.gkResponse = new VerifyCredentialResponse(response.getTimeout()); + result.gkResponse = VerifyCredentialResponse.fromTimeout(response.getTimeout()); return result; } else { result.gkResponse = VerifyCredentialResponse.ERROR; @@ -1096,12 +1099,12 @@ public class SyntheticPasswordManager { } VerifyCredentialResponse response = weaverVerify(slotId, null); if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK || - response.getPayload() == null) { + response.getGatekeeperHAT() == null) { Slog.e(TAG, "Failed to retrieve weaver secret when unwrapping token"); result.gkResponse = VerifyCredentialResponse.ERROR; return result; } - secdiscardable = SyntheticPasswordCrypto.decrypt(response.getPayload(), + secdiscardable = SyntheticPasswordCrypto.decrypt(response.getGatekeeperHAT(), PERSONALISATION_WEAVER_TOKEN, secdiscardable); } byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable); @@ -1174,6 +1177,12 @@ public class SyntheticPasswordManager { */ public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, @NonNull AuthenticationToken auth, long challenge, int userId) { + return verifyChallengeInternal(gatekeeper, auth.deriveGkPassword(), challenge, userId); + } + + protected @Nullable VerifyCredentialResponse verifyChallengeInternal( + IGateKeeperService gatekeeper, @NonNull byte[] gatekeeperPassword, long challenge, + int userId) { byte[] spHandle = loadSyntheticPasswordHandle(userId); if (spHandle == null) { // There is no password handle associated with the given user, i.e. the user is not @@ -1183,18 +1192,19 @@ public class SyntheticPasswordManager { GateKeeperResponse response; try { response = gatekeeper.verifyChallenge(userId, challenge, - spHandle, auth.deriveGkPassword()); + spHandle, gatekeeperPassword); } catch (RemoteException e) { Slog.e(TAG, "Fail to verify with gatekeeper " + userId, e); return VerifyCredentialResponse.ERROR; } int responseCode = response.getResponseCode(); if (responseCode == GateKeeperResponse.RESPONSE_OK) { - VerifyCredentialResponse result = new VerifyCredentialResponse(response.getPayload()); + VerifyCredentialResponse result = new VerifyCredentialResponse.Builder() + .setGatekeeperHAT(response.getPayload()).build(); if (response.getShouldReEnroll()) { try { response = gatekeeper.enroll(userId, spHandle, spHandle, - auth.deriveGkPassword()); + gatekeeperPassword); } catch (RemoteException e) { Slog.e(TAG, "Failed to invoke gatekeeper.enroll", e); response = GateKeeperResponse.ERROR; @@ -1203,7 +1213,8 @@ public class SyntheticPasswordManager { spHandle = response.getPayload(); saveSyntheticPasswordHandle(spHandle, userId); // Call self again to re-verify with updated handle - return verifyChallenge(gatekeeper, auth, challenge, userId); + return verifyChallengeInternal(gatekeeper, gatekeeperPassword, challenge, + userId); } else { // Fall through, return result from the previous verification attempt. Slog.w(TAG, "Fail to re-enroll SP handle for user " + userId); @@ -1211,7 +1222,7 @@ public class SyntheticPasswordManager { } return result; } else if (responseCode == GateKeeperResponse.RESPONSE_RETRY) { - return new VerifyCredentialResponse(response.getTimeout()); + return VerifyCredentialResponse.fromTimeout(response.getTimeout()); } else { return VerifyCredentialResponse.ERROR; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 3bd18f9a360f..006d78e4a648 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -70,9 +70,9 @@ public class NetworkPolicyLogger { static final int NTWK_BLOCKED_POWER = 0; static final int NTWK_ALLOWED_NON_METERED = 1; - static final int NTWK_BLOCKED_BLACKLIST = 2; - static final int NTWK_ALLOWED_WHITELIST = 3; - static final int NTWK_ALLOWED_TMP_WHITELIST = 4; + static final int NTWK_BLOCKED_DENYLIST = 2; + static final int NTWK_ALLOWED_ALLOWLIST = 3; + static final int NTWK_ALLOWED_TMP_ALLOWLIST = 4; static final int NTWK_BLOCKED_BG_RESTRICT = 5; static final int NTWK_ALLOWED_DEFAULT = 6; static final int NTWK_ALLOWED_SYSTEM = 7; @@ -269,12 +269,12 @@ public class NetworkPolicyLogger { return "blocked by power restrictions"; case NTWK_ALLOWED_NON_METERED: return "allowed on unmetered network"; - case NTWK_BLOCKED_BLACKLIST: - return "blacklisted on metered network"; - case NTWK_ALLOWED_WHITELIST: - return "whitelisted on metered network"; - case NTWK_ALLOWED_TMP_WHITELIST: - return "temporary whitelisted on metered network"; + case NTWK_BLOCKED_DENYLIST: + return "denylisted on metered network"; + case NTWK_ALLOWED_ALLOWLIST: + return "allowlisted on metered network"; + case NTWK_ALLOWED_TMP_ALLOWLIST: + return "temporary allowlisted on metered network"; case NTWK_BLOCKED_BG_RESTRICT: return "blocked when background is restricted"; case NTWK_ALLOWED_DEFAULT: diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index d6557f6410ec..295143e76235 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -101,13 +101,13 @@ import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; +import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_ALLOWLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_DEFAULT; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_NON_METERED; import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_SYSTEM; -import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_WHITELIST; -import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_WHITELIST; +import static com.android.server.net.NetworkPolicyLogger.NTWK_ALLOWED_TMP_ALLOWLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BG_RESTRICT; -import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_BLACKLIST; +import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_DENYLIST; import static com.android.server.net.NetworkPolicyLogger.NTWK_BLOCKED_POWER; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED; @@ -507,7 +507,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * UIDs that have been initially white-listed by system to avoid restricted background. */ @GuardedBy("mUidRulesFirstLock") - private final SparseBooleanArray mDefaultRestrictBackgroundWhitelistUids = + private final SparseBooleanArray mDefaultRestrictBackgroundAllowlistUids = new SparseBooleanArray(); /** @@ -515,7 +515,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * but later revoked by user. */ @GuardedBy("mUidRulesFirstLock") - private final SparseBooleanArray mRestrictBackgroundWhitelistRevokedUids = + private final SparseBooleanArray mRestrictBackgroundAllowlistRevokedUids = new SparseBooleanArray(); /** Set of ifaces that are metered. */ @@ -582,7 +582,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray(); - // TODO: keep whitelist of system-critical services that should never have + // TODO: keep allowlist of system-critical services that should never have // rules enforced, such as system, phone, and radio UIDs. // TODO: migrate notifications to SystemUI @@ -668,26 +668,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Whitelists pre-defined apps for restrict background, but only if the user didn't already - * revoke the whitelist. + * Allows pre-defined apps for restrict background, but only if the user didn't already + * revoked them. * - * @return whether any uid has been whitelisted. + * @return whether any uid has been allowlisted. */ @GuardedBy("mUidRulesFirstLock") - boolean addDefaultRestrictBackgroundWhitelistUidsUL() { + boolean addDefaultRestrictBackgroundAllowlistUidsUL() { final List<UserInfo> users = mUserManager.getUsers(); final int numberUsers = users.size(); boolean changed = false; for (int i = 0; i < numberUsers; i++) { final UserInfo user = users.get(i); - changed = addDefaultRestrictBackgroundWhitelistUidsUL(user.id) || changed; + changed = addDefaultRestrictBackgroundAllowlistUidsUL(user.id) || changed; } return changed; } @GuardedBy("mUidRulesFirstLock") - private boolean addDefaultRestrictBackgroundWhitelistUidsUL(int userId) { + private boolean addDefaultRestrictBackgroundAllowlistUidsUL(int userId) { final SystemConfig sysConfig = SystemConfig.getInstance(); final PackageManager pm = mContext.getPackageManager(); final ArraySet<String> allowDataUsage = sysConfig.getAllowInDataUsageSave(); @@ -695,7 +695,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (int i = 0; i < allowDataUsage.size(); i++) { final String pkg = allowDataUsage.valueAt(i); if (LOGD) - Slog.d(TAG, "checking restricted background whitelisting for package " + pkg + Slog.d(TAG, "checking restricted background allowlisting for package " + pkg + " and user " + userId); final ApplicationInfo app; try { @@ -706,20 +706,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { continue; } if (!app.isPrivilegedApp()) { - Slog.e(TAG, "addDefaultRestrictBackgroundWhitelistUidsUL(): " + Slog.e(TAG, "addDefaultRestrictBackgroundAllowlistUidsUL(): " + "skipping non-privileged app " + pkg); continue; } final int uid = UserHandle.getUid(userId, app.uid); - mDefaultRestrictBackgroundWhitelistUids.append(uid, true); + mDefaultRestrictBackgroundAllowlistUids.append(uid, true); if (LOGD) Slog.d(TAG, "Adding uid " + uid + " (user " + userId + ") to default restricted " - + "background whitelist. Revoked status: " - + mRestrictBackgroundWhitelistRevokedUids.get(uid)); - if (!mRestrictBackgroundWhitelistRevokedUids.get(uid)) { + + "background allowlist. Revoked status: " + + mRestrictBackgroundAllowlistRevokedUids.get(uid)); + if (!mRestrictBackgroundAllowlistRevokedUids.get(uid)) { if (LOGD) Slog.d(TAG, "adding default package " + pkg + " (uid " + uid + " for user " - + userId + ") to restrict background whitelist"); + + userId + ") to restrict background allowlist"); setUidPolicyUncheckedUL(uid, POLICY_ALLOW_METERED_BACKGROUND, false); changed = true; } @@ -799,7 +799,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }); - if (addDefaultRestrictBackgroundWhitelistUidsUL()) { + if (addDefaultRestrictBackgroundAllowlistUidsUL()) { writePolicyAL(); } @@ -1005,14 +1005,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case ACTION_USER_ADDED: synchronized (mUidRulesFirstLock) { // Remove any persistable state for the given user; both cleaning up after a - // USER_REMOVED, and one last sanity check during USER_ADDED + // USER_REMOVED, and one last check during USER_ADDED removeUserStateUL(userId, true, false); // Removing outside removeUserStateUL since that can also be called when // user resets app preferences. mMeteredRestrictedUids.remove(userId); if (action == ACTION_USER_ADDED) { - // Add apps that are whitelisted by default. - addDefaultRestrictBackgroundWhitelistUidsUL(userId); + // Add apps that are allowlisted by default. + addDefaultRestrictBackgroundAllowlistUidsUL(userId); } // Update global restrict for that user synchronized (mNetworkPoliciesSecondLock) { @@ -2196,12 +2196,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { in.setInput(fis, StandardCharsets.UTF_8.name()); // Must save the <restrict-background> tags and convert them to <uid-policy> later, - // to skip UIDs that were explicitly blacklisted. - final SparseBooleanArray whitelistedRestrictBackground = new SparseBooleanArray(); + // to skip UIDs that were explicitly denylisted. + final SparseBooleanArray allowlistedRestrictBackground = new SparseBooleanArray(); int type; int version = VERSION_INIT; - boolean insideWhitelist = false; + boolean insideAllowlist = false; while ((type = in.next()) != END_DOCUMENT) { final String tag = in.getName(); if (type == START_TAG) { @@ -2340,28 +2340,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); } } else if (TAG_WHITELIST.equals(tag)) { - insideWhitelist = true; - } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) { + insideAllowlist = true; + } else if (TAG_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) { final int uid = readIntAttribute(in, ATTR_UID); - whitelistedRestrictBackground.append(uid, true); - } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideWhitelist) { + allowlistedRestrictBackground.append(uid, true); + } else if (TAG_REVOKED_RESTRICT_BACKGROUND.equals(tag) && insideAllowlist) { final int uid = readIntAttribute(in, ATTR_UID); - mRestrictBackgroundWhitelistRevokedUids.put(uid, true); + mRestrictBackgroundAllowlistRevokedUids.put(uid, true); } } else if (type == END_TAG) { if (TAG_WHITELIST.equals(tag)) { - insideWhitelist = false; + insideAllowlist = false; } } } - final int size = whitelistedRestrictBackground.size(); + final int size = allowlistedRestrictBackground.size(); for (int i = 0; i < size; i++) { - final int uid = whitelistedRestrictBackground.keyAt(i); + final int uid = allowlistedRestrictBackground.keyAt(i); final int policy = mUidPolicy.get(uid, POLICY_NONE); if ((policy & POLICY_REJECT_METERED_BACKGROUND) != 0) { - Slog.w(TAG, "ignoring restrict-background-whitelist for " + uid + Slog.w(TAG, "ignoring restrict-background-allowlist for " + uid + " because its policy is " + uidPoliciesToString(policy)); continue; } @@ -2533,13 +2533,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { out.endTag(null, TAG_POLICY_LIST); - // write all whitelists + // write all allowlists out.startTag(null, TAG_WHITELIST); - // revoked restrict background whitelist - int size = mRestrictBackgroundWhitelistRevokedUids.size(); + // revoked restrict background allowlist + int size = mRestrictBackgroundAllowlistRevokedUids.size(); for (int i = 0; i < size; i++) { - final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i); + final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i); out.startTag(null, TAG_REVOKED_RESTRICT_BACKGROUND); writeIntAttribute(out, ATTR_UID, uid); out.endTag(null, TAG_REVOKED_RESTRICT_BACKGROUND); @@ -2619,21 +2619,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { setUidPolicyUncheckedUL(uid, policy, false); final boolean notifyApp; - if (!isUidValidForWhitelistRulesUL(uid)) { + if (!isUidValidForAllowlistRulesUL(uid)) { notifyApp = false; } else { - final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; - final boolean isBlacklisted = policy == POLICY_REJECT_METERED_BACKGROUND; - final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; - final boolean isWhitelisted = policy == POLICY_ALLOW_METERED_BACKGROUND; - final boolean wasBlocked = wasBlacklisted || (mRestrictBackground && !wasWhitelisted); - final boolean isBlocked = isBlacklisted || (mRestrictBackground && !isWhitelisted); - if ((wasWhitelisted && (!isWhitelisted || isBlacklisted)) - && mDefaultRestrictBackgroundWhitelistUids.get(uid) - && !mRestrictBackgroundWhitelistRevokedUids.get(uid)) { + final boolean wasDenylisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; + final boolean isDenylisted = policy == POLICY_REJECT_METERED_BACKGROUND; + final boolean wasAllowlisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; + final boolean isAllowlisted = policy == POLICY_ALLOW_METERED_BACKGROUND; + final boolean wasBlocked = wasDenylisted || (mRestrictBackground && !wasAllowlisted); + final boolean isBlocked = isDenylisted || (mRestrictBackground && !isAllowlisted); + if ((wasAllowlisted && (!isAllowlisted || isDenylisted)) + && mDefaultRestrictBackgroundAllowlistUids.get(uid) + && !mRestrictBackgroundAllowlistRevokedUids.get(uid)) { if (LOGD) - Slog.d(TAG, "Adding uid " + uid + " to revoked restrict background whitelist"); - mRestrictBackgroundWhitelistRevokedUids.append(uid, true); + Slog.d(TAG, "Adding uid " + uid + " to revoked restrict background allowlist"); + mRestrictBackgroundAllowlistRevokedUids.append(uid, true); } notifyApp = wasBlocked != isBlocked; } @@ -2700,11 +2700,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mLogger.removingUserState(userId); boolean changed = false; - // Remove entries from revoked default restricted background UID whitelist - for (int i = mRestrictBackgroundWhitelistRevokedUids.size() - 1; i >= 0; i--) { - final int uid = mRestrictBackgroundWhitelistRevokedUids.keyAt(i); + // Remove entries from revoked default restricted background UID allowlist + for (int i = mRestrictBackgroundAllowlistRevokedUids.size() - 1; i >= 0; i--) { + final int uid = mRestrictBackgroundAllowlistRevokedUids.keyAt(i); if (UserHandle.getUserId(uid) == userId) { - mRestrictBackgroundWhitelistRevokedUids.removeAt(i); + mRestrictBackgroundAllowlistRevokedUids.removeAt(i); changed = true; } } @@ -2913,7 +2913,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.d(TAG, "setRestrictBackgroundUL(): " + restrictBackground + "; reason: " + reason); final boolean oldRestrictBackground = mRestrictBackground; mRestrictBackground = restrictBackground; - // Must whitelist foreground apps before turning data saver mode on. + // Must allowlist foreground apps before turning data saver mode on. // TODO: there is no need to iterate through all apps here, just those in the foreground, // so it could call AM to get the UIDs of such apps, and iterate through them instead. updateRulesForRestrictBackgroundUL(); @@ -2966,7 +2966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Binder.restoreCallingIdentity(token); } if (policy == POLICY_REJECT_METERED_BACKGROUND) { - // App is blacklisted. + // App is denylisted. return RESTRICT_BACKGROUND_STATUS_ENABLED; } if (!mRestrictBackground) { @@ -3543,25 +3543,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.decreaseIndent(); } - size = mDefaultRestrictBackgroundWhitelistUids.size(); + size = mDefaultRestrictBackgroundAllowlistUids.size(); if (size > 0) { - fout.println("Default restrict background whitelist uids:"); + fout.println("Default restrict background allowlist uids:"); fout.increaseIndent(); for (int i = 0; i < size; i++) { fout.print("UID="); - fout.print(mDefaultRestrictBackgroundWhitelistUids.keyAt(i)); + fout.print(mDefaultRestrictBackgroundAllowlistUids.keyAt(i)); fout.println(); } fout.decreaseIndent(); } - size = mRestrictBackgroundWhitelistRevokedUids.size(); + size = mRestrictBackgroundAllowlistRevokedUids.size(); if (size > 0) { - fout.println("Default restrict background whitelist uids revoked by users:"); + fout.println("Default restrict background allowlist uids revoked by users:"); fout.increaseIndent(); for (int i = 0; i < size; i++) { fout.print("UID="); - fout.print(mRestrictBackgroundWhitelistRevokedUids.keyAt(i)); + fout.print(mRestrictBackgroundAllowlistRevokedUids.keyAt(i)); fout.println(); } fout.decreaseIndent(); @@ -3882,7 +3882,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") void updateRuleForAppIdleUL(int uid) { - if (!isUidValidForBlacklistRulesUL(uid)) return; + if (!isUidValidForDenylistRulesUL(uid)) return; if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRuleForAppIdleUL: " + uid ); @@ -3915,13 +3915,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final SparseIntArray blockedUids = new SparseIntArray(); for (int i = 0; i < ruleCount; i++) { final int uid = mUidFirewallStandbyRules.keyAt(i); - if (!isUidValidForBlacklistRulesUL(uid)) { + if (!isUidValidForDenylistRulesUL(uid)) { continue; } int oldRules = mUidRules.get(uid); if (enableChain) { // Chain wasn't enabled before and the other power-related - // chains are whitelists, so we can clear the + // chains are allowlists, so we can clear the // MASK_ALL_NETWORKS part of the rules and re-inform listeners if // the effective rules result in blocking network access. oldRules &= MASK_METERED_NETWORKS; @@ -4079,10 +4079,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // TODO: the MEDIA / DRM restriction might not be needed anymore, in which case both // methods below could be merged into a isUidValidForRules() method. @GuardedBy("mUidRulesFirstLock") - private boolean isUidValidForBlacklistRulesUL(int uid) { + private boolean isUidValidForDenylistRulesUL(int uid) { // allow rules on specific system services, and any apps if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID - || isUidValidForWhitelistRulesUL(uid)) { + || isUidValidForAllowlistRulesUL(uid)) { return true; } @@ -4090,7 +4090,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @GuardedBy("mUidRulesFirstLock") - private boolean isUidValidForWhitelistRulesUL(int uid) { + private boolean isUidValidForAllowlistRulesUL(int uid) { return UserHandle.isApp(uid) && hasInternetPermissionUL(uid); } @@ -4235,23 +4235,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Applies network rules to bandwidth controllers based on process state and user-defined - * restrictions (blacklist / whitelist). + * restrictions (allowlist / denylist). * * <p> * {@code netd} defines 3 firewall chains that govern whether an app has access to metered * networks: * <ul> - * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (blacklist). - * <li>@{code bw_happy_box}: UIDs added to this chain have access (whitelist), unless they're - * also blacklisted. + * <li>@{code bw_penalty_box}: UIDs added to this chain do not have access (denylist). + * <li>@{code bw_happy_box}: UIDs added to this chain have access (allowlist), unless they're + * also denylisted. * <li>@{code bw_data_saver}: when enabled (through {@link #setRestrictBackground(boolean)}), - * no UIDs other than those whitelisted will have access. + * no UIDs other than those allowlisted will have access. * <ul> * * <p>The @{code bw_penalty_box} and @{code bw_happy_box} are primarily managed through the - * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundWhitelistedUid(int)} / - * {@link #removeRestrictBackgroundWhitelistedUid(int)} methods (for blacklist and whitelist - * respectively): these methods set the proper internal state (blacklist / whitelist), then call + * {@link #setUidPolicy(int, int)} and {@link #addRestrictBackgroundAllowlistedUid(int)} / + * {@link #removeRestrictBackgroundDenylistedUid(int)} methods (for denylist and allowlist + * respectively): these methods set the proper internal state (denylist / allowlist), then call * this ({@link #updateRulesForDataUsageRestrictionsUL(int)}) to propagate the rules to * {@link INetworkManagementService}, but this method should also be called in events (like * Data Saver Mode flips or UID state changes) that might affect the foreground app, since the @@ -4260,7 +4260,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * <ul> * <li>When Data Saver mode is on, the foreground app should be temporarily added to * {@code bw_happy_box} before the @{code bw_data_saver} chain is enabled. - * <li>If the foreground app is blacklisted by the user, it should be temporarily removed from + * <li>If the foreground app is denylisted by the user, it should be temporarily removed from * {@code bw_penalty_box}. * <li>When the app leaves foreground state, the temporary changes above should be reverted. * </ul> @@ -4285,7 +4285,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void updateRulesForDataUsageRestrictionsULInner(int uid) { - if (!isUidValidForWhitelistRulesUL(uid)) { + if (!isUidValidForAllowlistRulesUL(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict data rules for uid " + uid); return; } @@ -4295,8 +4295,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); - final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; - final boolean isWhitelisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; + final boolean isDenylisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; + final boolean isAllowlisted = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; final int oldRule = oldUidRules & MASK_METERED_NETWORKS; int newRule = RULE_NONE; @@ -4304,15 +4304,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (isRestrictedByAdmin) { newRule = RULE_REJECT_METERED; } else if (isForeground) { - if (isBlacklisted || (mRestrictBackground && !isWhitelisted)) { + if (isDenylisted || (mRestrictBackground && !isAllowlisted)) { newRule = RULE_TEMPORARY_ALLOW_METERED; - } else if (isWhitelisted) { + } else if (isAllowlisted) { newRule = RULE_ALLOW_METERED; } } else { - if (isBlacklisted) { + if (isDenylisted) { newRule = RULE_REJECT_METERED; - } else if (mRestrictBackground && isWhitelisted) { + } else if (mRestrictBackground && isAllowlisted) { newRule = RULE_ALLOW_METERED; } } @@ -4321,8 +4321,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + ": isForeground=" +isForeground - + ", isBlacklisted=" + isBlacklisted - + ", isWhitelisted=" + isWhitelisted + + ", isDenylisted=" + isDenylisted + + ", isAllowlisted=" + isAllowlisted + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", oldRule=" + uidRulesToString(oldRule) + ", newRule=" + uidRulesToString(newRule) @@ -4339,49 +4339,49 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Second step: apply bw changes based on change of state. if (newRule != oldRule) { if (hasRule(newRule, RULE_TEMPORARY_ALLOW_METERED)) { - // Temporarily whitelist foreground app, removing from blacklist if necessary + // Temporarily allowlist foreground app, removing from denylist if necessary // (since bw_penalty_box prevails over bw_happy_box). - setMeteredNetworkWhitelist(uid, true); + setMeteredNetworkAllowlist(uid, true); // TODO: if statement below is used to avoid an unnecessary call to netd / iptables, // but ideally it should be just: - // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (isBlacklisted) { - setMeteredNetworkBlacklist(uid, false); + // setMeteredNetworkDenylist(uid, isDenylisted); + if (isDenylisted) { + setMeteredNetworkDenylist(uid, false); } } else if (hasRule(oldRule, RULE_TEMPORARY_ALLOW_METERED)) { - // Remove temporary whitelist from app that is not on foreground anymore. + // Remove temporary allowlist from app that is not on foreground anymore. // TODO: if statements below are used to avoid unnecessary calls to netd / iptables, // but ideally they should be just: - // setMeteredNetworkWhitelist(uid, isWhitelisted); - // setMeteredNetworkBlacklist(uid, isBlacklisted); - if (!isWhitelisted) { - setMeteredNetworkWhitelist(uid, false); + // setMeteredNetworkAllowlist(uid, isAllowlisted); + // setMeteredNetworkDenylist(uid, isDenylisted); + if (!isAllowlisted) { + setMeteredNetworkAllowlist(uid, false); } - if (isBlacklisted || isRestrictedByAdmin) { - setMeteredNetworkBlacklist(uid, true); + if (isDenylisted || isRestrictedByAdmin) { + setMeteredNetworkDenylist(uid, true); } } else if (hasRule(newRule, RULE_REJECT_METERED) || hasRule(oldRule, RULE_REJECT_METERED)) { - // Flip state because app was explicitly added or removed to blacklist. - setMeteredNetworkBlacklist(uid, (isBlacklisted || isRestrictedByAdmin)); - if (hasRule(oldRule, RULE_REJECT_METERED) && isWhitelisted) { - // Since blacklist prevails over whitelist, we need to handle the special case - // where app is whitelisted and blacklisted at the same time (although such - // scenario should be blocked by the UI), then blacklist is removed. - setMeteredNetworkWhitelist(uid, isWhitelisted); + // Flip state because app was explicitly added or removed to denylist. + setMeteredNetworkDenylist(uid, (isDenylisted || isRestrictedByAdmin)); + if (hasRule(oldRule, RULE_REJECT_METERED) && isAllowlisted) { + // Since dneylist prevails over allowlist, we need to handle the special case + // where app is allowlisted and denylisted at the same time (although such + // scenario should be blocked by the UI), then denylist is removed. + setMeteredNetworkAllowlist(uid, isAllowlisted); } } else if (hasRule(newRule, RULE_ALLOW_METERED) || hasRule(oldRule, RULE_ALLOW_METERED)) { - // Flip state because app was explicitly added or removed to whitelist. - setMeteredNetworkWhitelist(uid, isWhitelisted); + // Flip state because app was explicitly added or removed to allowlist. + setMeteredNetworkAllowlist(uid, isAllowlisted); } else { // All scenarios should have been covered above. Log.wtf(TAG, "Unexpected change of metered UID state for " + uid + ": foreground=" + isForeground - + ", whitelisted=" + isWhitelisted - + ", blacklisted=" + isBlacklisted + + ", allowlisted=" + isAllowlisted + + ", denylisted=" + isDenylisted + ", isRestrictedByAdmin=" + isRestrictedByAdmin + ", newRule=" + uidRulesToString(newUidRules) + ", oldRule=" + uidRulesToString(oldUidRules)); @@ -4397,7 +4397,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * listeners in case of change. * <p> * There are 3 power-related rules that affects whether an app has background access on - * non-metered networks, and when the condition applies and the UID is not whitelisted for power + * non-metered networks, and when the condition applies and the UID is not allowlisted for power * restriction, it's added to the equivalent firewall chain: * <ul> * <li>App is idle: {@code fw_standby} firewall chain. @@ -4406,7 +4406,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * </ul> * <p> * This method updates the power-related part of the {@link #mUidRules} for a given uid based on - * these modes, the UID process state (foreground or not), and the UIDwhitelist state. + * these modes, the UID process state (foreground or not), and the UID allowlist state. * <p> * <strong>NOTE: </strong>This method does not update the firewall rules on {@code netd}. */ @@ -4450,7 +4450,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mUidRulesFirstLock") private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean isUidIdle) { - if (!isUidValidForBlacklistRulesUL(uid)) { + if (!isUidValidForDenylistRulesUL(uid)) { if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid); return RULE_NONE; } @@ -4859,23 +4859,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private void setMeteredNetworkBlacklist(int uid, boolean enable) { - if (LOGV) Slog.v(TAG, "setMeteredNetworkBlacklist " + uid + ": " + enable); + private void setMeteredNetworkDenylist(int uid, boolean enable) { + if (LOGV) Slog.v(TAG, "setMeteredNetworkDenylist " + uid + ": " + enable); try { - mNetworkManager.setUidMeteredNetworkBlacklist(uid, enable); + mNetworkManager.setUidMeteredNetworkDenylist(uid, enable); } catch (IllegalStateException e) { - Log.wtf(TAG, "problem setting blacklist (" + enable + ") rules for " + uid, e); + Log.wtf(TAG, "problem setting denylist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { // ignored; service lives in system_server } } - private void setMeteredNetworkWhitelist(int uid, boolean enable) { - if (LOGV) Slog.v(TAG, "setMeteredNetworkWhitelist " + uid + ": " + enable); + private void setMeteredNetworkAllowlist(int uid, boolean enable) { + if (LOGV) Slog.v(TAG, "setMeteredNetworkAllowlist " + uid + ": " + enable); try { - mNetworkManager.setUidMeteredNetworkWhitelist(uid, enable); + mNetworkManager.setUidMeteredNetworkAllowlist(uid, enable); } catch (IllegalStateException e) { - Log.wtf(TAG, "problem setting whitelist (" + enable + ") rules for " + uid, e); + Log.wtf(TAG, "problem setting allowlist (" + enable + ") rules for " + uid, e); } catch (RemoteException e) { // ignored; service lives in system_server } @@ -4936,7 +4936,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Add or remove a uid to the firewall blacklist for all network ifaces. + * Add or remove a uid to the firewall denylist for all network ifaces. */ private void setUidFirewallRule(int chain, int uid, int rule) { if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) { @@ -4966,7 +4966,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } /** - * Add or remove a uid to the firewall blacklist for all network ifaces. + * Add or remove a uid to the firewall denylist for all network ifaces. */ @GuardedBy("mUidRulesFirstLock") private void enableFirewallChainUL(int chain, boolean enable) { @@ -4995,8 +4995,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkManager.setFirewallUidRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT); mNetworkManager .setFirewallUidRule(FIREWALL_CHAIN_POWERSAVE, uid, FIREWALL_RULE_DEFAULT); - mNetworkManager.setUidMeteredNetworkWhitelist(uid, false); - mNetworkManager.setUidMeteredNetworkBlacklist(uid, false); + mNetworkManager.setUidMeteredNetworkAllowlist(uid, false); + mNetworkManager.setUidMeteredNetworkDenylist(uid, false); } catch (IllegalStateException e) { Log.wtf(TAG, "problem resetting firewall uid rules for " + uid, e); } catch (RemoteException e) { @@ -5189,13 +5189,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { reason = NTWK_ALLOWED_NON_METERED; } else if (hasRule(uidRules, RULE_REJECT_METERED)) { - reason = NTWK_BLOCKED_BLACKLIST; + reason = NTWK_BLOCKED_DENYLIST; } else if (hasRule(uidRules, RULE_ALLOW_METERED)) { - reason = NTWK_ALLOWED_WHITELIST; + reason = NTWK_ALLOWED_ALLOWLIST; } else if (hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED)) { - reason = NTWK_ALLOWED_TMP_WHITELIST; + reason = NTWK_ALLOWED_TMP_ALLOWLIST; } else if (isBackgroundRestricted) { reason = NTWK_BLOCKED_BG_RESTRICT; @@ -5208,13 +5208,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { switch(reason) { case NTWK_ALLOWED_DEFAULT: case NTWK_ALLOWED_NON_METERED: - case NTWK_ALLOWED_TMP_WHITELIST: - case NTWK_ALLOWED_WHITELIST: + case NTWK_ALLOWED_TMP_ALLOWLIST: + case NTWK_ALLOWED_ALLOWLIST: case NTWK_ALLOWED_SYSTEM: blocked = false; break; case NTWK_BLOCKED_POWER: - case NTWK_BLOCKED_BLACKLIST: + case NTWK_BLOCKED_DENYLIST: case NTWK_BLOCKED_BG_RESTRICT: blocked = true; break; @@ -5234,7 +5234,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public void resetUserState(int userId) { synchronized (mUidRulesFirstLock) { boolean changed = removeUserStateUL(userId, false, true); - changed = addDefaultRestrictBackgroundWhitelistUidsUL(userId) || changed; + changed = addDefaultRestrictBackgroundAllowlistUidsUL(userId) || changed; if (changed) { synchronized (mNetworkPoliciesSecondLock) { writePolicyAL(); 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/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/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index bf9506ad51f1..8b2ba9c98f23 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4786,6 +4786,7 @@ public class UserManagerService extends IUserManager.Stub { } } + pw.println(); pw.println("Device properties:"); pw.println(" Device owner id:" + mDeviceOwnerUserId); pw.println(); @@ -4814,12 +4815,9 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(']'); } - synchronized (mUsersLock) { - pw.println(); - pw.print("Cached user IDs: "); + pw.print(" Cached user IDs: "); pw.println(Arrays.toString(mUserIds)); - pw.println(); } } // synchronized (mPackagesLock) diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 3c1d189dc102..f7e9e34a4702 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -139,6 +139,11 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_CONFIG_PRIVATE_DNS }); + public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet( + UserManager.DISALLOW_ADD_MANAGED_PROFILE, + UserManager.DISALLOW_REMOVE_MANAGED_PROFILE + ); + /** * Set of user restriction which we don't want to persist. */ diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 03868e922bdd..548cd70de4d1 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -450,7 +450,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { volatile int mPendingWakeKey = PENDING_KEY_NULL; int mRecentAppsHeldModifiers; - boolean mLanguageSwitchKeyPressed; int mCameraLensCoverState = CAMERA_LENS_COVER_ABSENT; boolean mHaveBuiltInKeyboard; @@ -933,6 +932,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + final boolean handledByPowerManager = mPowerManagerInternal.interceptPowerKeyDown(event); + GestureLauncherService gestureService = LocalServices.getService( GestureLauncherService.class); boolean gesturedServiceIntercepted = false; @@ -952,7 +953,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. @@ -2935,12 +2937,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction); return -1; } - if (mLanguageSwitchKeyPressed && !down - && (keyCode == KeyEvent.KEYCODE_LANGUAGE_SWITCH - || keyCode == KeyEvent.KEYCODE_SPACE)) { - mLanguageSwitchKeyPressed = false; - return -1; - } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { 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/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index 4349ca451c36..2a74b3d23829 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -28,6 +28,8 @@ import static android.os.Process.SYSTEM_UID; import android.Manifest.permission; import android.annotation.NonNull; import android.app.AppOpsManager; +import android.app.role.OnRoleHoldersChangedListener; +import android.app.role.RoleManager; import android.app.slice.ISliceManager; import android.app.slice.SliceSpec; import android.app.usage.UsageStatsManagerInternal; @@ -77,6 +79,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.function.Supplier; public class SliceManagerService extends ISliceManager.Stub { @@ -121,6 +124,7 @@ public class SliceManagerService extends ISliceManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); + mRoleObserver = new RoleObserver(); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); } @@ -478,10 +482,26 @@ public class SliceManagerService extends ISliceManager.Stub { return cn.getPackageName(); } + /** + * A cached value of the default home app + */ + private String mCachedDefaultHome = null; + // Based on getDefaultHome in ShortcutService. // TODO: Unify if possible @VisibleForTesting protected String getDefaultHome(int userId) { + + // Set VERIFY to true to run the cache in "shadow" mode for cache + // testing. Do not commit set to true; + final boolean VERIFY = false; + + if (mCachedDefaultHome != null) { + if (!VERIFY) { + return mCachedDefaultHome; + } + } + final long token = Binder.clearCallingIdentity(); try { final List<ResolveInfo> allHomeCandidates = new ArrayList<>(); @@ -490,10 +510,12 @@ public class SliceManagerService extends ISliceManager.Stub { final ComponentName defaultLauncher = mPackageManagerInternal .getHomeActivitiesAsUser(allHomeCandidates, userId); - ComponentName detected = null; - if (defaultLauncher != null) { - detected = defaultLauncher; - } + ComponentName detected = defaultLauncher; + + // Cache the default launcher. It is not a problem if the + // launcher is null - eventually, the default launcher will be + // set to something non-null. + mCachedDefaultHome = ((detected != null) ? detected.getPackageName() : null); if (detected == null) { // If we reach here, that means it's the first check since the user was created, @@ -517,12 +539,54 @@ public class SliceManagerService extends ISliceManager.Stub { lastPriority = ri.priority; } } - return detected != null ? detected.getPackageName() : null; + final String ret = ((detected != null) ? detected.getPackageName() : null); + if (VERIFY) { + if (mCachedDefaultHome != null && !mCachedDefaultHome.equals(ret)) { + Slog.e(TAG, "getDefaultHome() cache failure, is " + + mCachedDefaultHome + " should be " + ret); + } + } + return ret; } finally { Binder.restoreCallingIdentity(token); } } + public void invalidateCachedDefaultHome() { + mCachedDefaultHome = null; + } + + /** + * Listen for changes in the roles, and invalidate the cached default + * home as necessary. + */ + private RoleObserver mRoleObserver; + + class RoleObserver implements OnRoleHoldersChangedListener { + private RoleManager mRm; + private final Executor mExecutor; + + RoleObserver() { + mExecutor = mContext.getMainExecutor(); + register(); + } + + public void register() { + mRm = mContext.getSystemService(RoleManager.class); + if (mRm != null) { + mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL); + invalidateCachedDefaultHome(); + } + } + + @Override + public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) { + if (RoleManager.ROLE_HOME.equals(roleName)) { + invalidateCachedDefaultHome(); + } + } + } + private boolean isGrantedFullAccess(String pkg, int userId) { return mPermissions.hasFullAccess(pkg, userId); } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index ecba3f9c27c4..1536473ff0a1 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -177,7 +177,7 @@ final class AccessibilityController { public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) { WindowsForAccessibilityObserver observer = null; - synchronized (mService) { + synchronized (mService.mGlobalLock) { final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(displayId); if (windowsForA11yObserver != null) { @@ -266,7 +266,7 @@ final class AccessibilityController { // Not relevant for the display magnifier. WindowsForAccessibilityObserver observer = null; - synchronized (mService) { + synchronized (mService.mGlobalLock) { final WindowsForAccessibilityObserver windowsForA11yObserver = mWindowsForAccessibilityObserver.get(displayId); if (windowsForA11yObserver != null) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index e573d362fef4..5b8078729eee 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -107,6 +107,12 @@ import static android.view.WindowManager.TRANSIT_TASK_CLOSE; import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_UNSET; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN; @@ -172,12 +178,6 @@ import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchi import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.Task.ActivityState.DESTROYED; @@ -294,6 +294,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.content.ReferrerIntent; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; @@ -305,7 +306,6 @@ import com.android.server.am.AppTimeTracker; import com.android.server.am.PendingIntentRecord; import com.android.server.display.color.ColorDisplayService; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.NeededUriGrants; import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; 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/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 11a468be8f9f..f76108f332d1 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -67,10 +67,10 @@ import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpe import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation; import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE; import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -127,11 +127,11 @@ import android.view.animation.TranslateAnimation; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils.Dump; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.AttributeCache; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.animation.ClipRectLRAnimation; import com.android.server.wm.animation.ClipRectTBAnimation; import com.android.server.wm.animation.CurvedTranslateAnimation; diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 5720e9b7f193..57d51c51c12b 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -41,14 +41,14 @@ import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE; import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN; import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; @@ -69,7 +69,7 @@ import android.view.WindowManager.TransitionType; import android.view.animation.Animation; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.ArrayList; import java.util.LinkedList; diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index f563e57b363e..0b2c851c4366 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -16,13 +16,13 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import android.graphics.Rect; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.function.Supplier; diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 6ffb48282017..8bd42f03ff86 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -24,11 +24,11 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER; import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.internal.util.Preconditions.checkState; import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA; import static com.android.server.wm.DisplayAreaProto.NAME; import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA; import android.annotation.Nullable; @@ -38,8 +38,8 @@ import android.util.proto.ProtoOutputStream; import android.window.DisplayAreaInfo; import android.window.IDisplayAreaOrganizer; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.util.Comparator; import java.util.function.BiFunction; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index fc170538994c..ba5a38290349 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -74,6 +74,14 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; import static android.window.DisplayAreaOrganizer.FEATURE_WINDOWED_MAGNIFICATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -94,14 +102,6 @@ import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA; import static com.android.server.wm.DisplayContentProto.ROTATION; import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION; import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -203,6 +203,7 @@ import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.function.TriConsumer; import com.android.internal.util.function.pooled.PooledConsumer; @@ -211,7 +212,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.utils.DisplayRotationUtil; import com.android.server.wm.utils.RotationCache; import com.android.server.wm.utils.WmDisplayCutout; @@ -4063,9 +4063,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM, "Taking screenshot while rotating"); // Send invalid rect and no width and height since it will screenshot the entire display. - Rect frame = new Rect(0, 0, -1, -1); - final Bitmap bitmap = SurfaceControl.screenshot(frame, 0, 0, inRotation, - mDisplay.getRotation()); + final IBinder displayToken = SurfaceControl.getInternalDisplayToken(); + final SurfaceControl.DisplayCaptureArgs captureArgs = + new SurfaceControl.DisplayCaptureArgs.Builder(displayToken) + .setUseIdentityTransform(inRotation) + .build(); + final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer = + SurfaceControl.captureDisplay(captureArgs); + final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); if (bitmap == null) { Slog.w(TAG_WM, "Failed to take screenshot"); return null; diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4f6f75d924c4..2e03cb80b189 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -112,6 +112,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; @@ -120,7 +121,6 @@ import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -187,6 +187,7 @@ import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.GestureNavigationSettingsObserver; import com.android.internal.policy.ScreenDecorationsUtils; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ScreenshotHelper; import com.android.internal.util.function.TriConsumer; import com.android.internal.view.AppearanceRegion; @@ -199,7 +200,6 @@ import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; import com.android.server.policy.WindowOrientationListener; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wallpaper.WallpaperManagerInternal; import com.android.server.wm.utils.InsetUtils; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index c63128c15e8d..0206787ef226 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -22,8 +22,8 @@ import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,12 +58,12 @@ import android.window.WindowContainerTransaction; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.UiThread; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowOrientationListener; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 22dd1d332345..133b11116460 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -18,11 +18,11 @@ package com.android.server.wm; import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.DragDropController.MSG_ANIMATION_END; import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT; import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,9 +58,9 @@ import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.view.IDragAndDropPermissions; import com.android.server.LocalServices; -import com.android.server.protolog.common.ProtoLog; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index e7fbc334306e..86e2698302aa 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -16,13 +16,13 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import android.view.InsetsSource; import android.view.WindowInsets; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 791f47128be0..0fe9735c9e46 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -41,7 +41,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -60,8 +60,8 @@ import android.view.InputEventReceiver; import android.view.InputWindowHandle; import android.view.SurfaceControl; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.Set; diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index f64149cee8c7..d1eb79556d1d 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -24,7 +24,7 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.ViewRootImpl.sNewInsetsMode; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL; import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED; @@ -40,8 +40,8 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.TriConsumer; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 9c978fd0c867..ab1074ee2821 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -30,7 +30,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; import android.annotation.NonNull; import android.annotation.Nullable; @@ -45,8 +45,8 @@ import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowManager; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.inputmethod.InputMethodManagerInternal; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; @@ -105,6 +105,10 @@ class InsetsStateController { * @return The state stripped of the necessary information. */ InsetsState getInsetsForDispatch(@NonNull WindowState target) { + final InsetsState rotatedState = target.mToken.getFixedRotationTransformInsetsState(); + if (rotatedState != null) { + return rotatedState; + } final InsetsSourceProvider provider = target.getControllableInsetProvider(); final @InternalInsetsType int type = provider != null ? provider.getSource().getType() : ITYPE_INVALID; diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index d7b43bc5537d..6c416830b59e 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -25,8 +25,8 @@ import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; @@ -41,9 +41,9 @@ import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 6b3a5d6bf18c..143fbb0fe48b 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -23,10 +23,10 @@ import static android.view.RemoteAnimationTarget.MODE_OPENING; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowManagerInternal.AppTransitionListener; @@ -56,12 +56,12 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.inputmethod.InputMethodManagerInternal; -import com.android.server.protolog.common.ProtoLog; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index c255a18190f7..e7461e7d5517 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -16,8 +16,8 @@ package com.android.server.wm; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -37,9 +37,9 @@ import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FastPrintWriter; -import com.android.server.protolog.ProtoLogImpl; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1cb483c1d1a0..b3a3ed7eeba4 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -41,6 +41,11 @@ import static android.view.WindowManager.TRANSIT_NONE; import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY; import static android.view.WindowManager.TRANSIT_TASK_TO_BACK; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; @@ -59,11 +64,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATE import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS; import static com.android.server.wm.ActivityTaskManagerService.ANIMATE; import static com.android.server.wm.ActivityTaskManagerService.TAG_SWITCH; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; @@ -146,6 +146,7 @@ import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; @@ -155,7 +156,6 @@ import com.android.server.am.ActivityManagerService; import com.android.server.am.AppTimeTracker; import com.android.server.am.UserState; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index d7b8fb00d05c..3c8036d4e3b6 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -18,9 +18,9 @@ package com.android.server.wm; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.AnimationSpecProto.ROTATE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; import static com.android.server.wm.RotationAnimationSpecProto.DURATION_MS; import static com.android.server.wm.RotationAnimationSpecProto.END_LUMA; import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA; @@ -50,7 +50,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Transformation; import com.android.internal.R; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; import com.android.server.wm.utils.RotationAnimationUtils; diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 86cbf3e3afe1..3b32a9d76258 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -24,7 +24,7 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -58,7 +58,7 @@ import android.view.SurfaceSession; import android.view.WindowManager; import com.android.internal.os.logging.MetricsLoggerWrapper; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.WindowManagerService.H; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index 1c9743041923..d9365c5d0666 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; @@ -28,7 +28,7 @@ import android.hardware.HardwareBuffer; import android.view.Surface; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.function.Supplier; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index be0815b06051..ec7b1eed7f91 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -78,6 +78,8 @@ import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT; import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP; import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN; import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; @@ -116,8 +118,6 @@ import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_ import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import static com.android.server.wm.Task.ActivityState.PAUSED; import static com.android.server.wm.Task.ActivityState.PAUSING; import static com.android.server.wm.Task.ActivityState.RESUMED; @@ -210,6 +210,7 @@ import android.window.ITaskOrganizer; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledFunction; @@ -218,7 +219,6 @@ import com.android.internal.util.function.pooled.PooledPredicate; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.AppTimeTracker; -import com.android.server.protolog.common.ProtoLog; import com.android.server.uri.NeededUriGrants; import org.xmlpull.v1.XmlPullParser; @@ -7056,17 +7056,21 @@ class Task extends WindowContainer<WindowContainer> { /** * Reset local parameters because an app's activity died. * @param app The app of the activity that died. + * @return {@code true} if the process of the pausing activity is died. */ - void handleAppDied(WindowProcessController app) { + boolean handleAppDied(WindowProcessController app) { + boolean isPausingDied = false; if (mPausingActivity != null && mPausingActivity.app == app) { if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE, "App died while pausing: " + mPausingActivity); mPausingActivity = null; + isPausingDied = true; } if (mLastPausedActivity != null && mLastPausedActivity.app == app) { mLastPausedActivity = null; mLastNoHistoryActivity = null; } + return isPausingDied; } boolean dump(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient, diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index a847744247c7..32511108836e 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -32,13 +32,13 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK; import static com.android.server.wm.DisplayContent.alwaysCreateStack; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.RootWindowContainer.TAG_STATES; import static com.android.server.wm.Task.ActivityState.RESUMED; import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE; @@ -58,10 +58,10 @@ import android.view.SurfaceControl; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.internal.util.function.pooled.PooledPredicate; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 3fbc0373e1a9..a66cd846e8be 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -26,8 +26,8 @@ import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -59,7 +59,7 @@ import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.internal.policy.TaskResizingAlgorithm.CtrlType; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; class TaskPositioner implements IBinder.DeathRecipient { private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false; diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java index 1103bf19b3bf..3def0911bd76 100644 --- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java +++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java @@ -15,14 +15,14 @@ */ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; import android.hardware.HardwareBuffer; import android.view.Surface; import android.view.SurfaceControl; import android.view.SurfaceSession; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.util.function.Function; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index 9b18ac8f7702..e9ada6be7e7b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -41,7 +41,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.TaskSnapshotController.getSystemBarInsets; import static com.android.server.wm.TaskSnapshotController.mergeInsetsSources; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -83,9 +83,9 @@ import android.view.WindowManagerGlobal; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.DecorView; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.view.BaseIWindow; import com.android.server.policy.WindowManagerPolicy.StartingSurface; -import com.android.server.protolog.common.ProtoLog; /** * This class represents a starting window that shows a snapshot. diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java index f46701536cf8..38bff9ed3c31 100644 --- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java +++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java @@ -15,8 +15,8 @@ */ package com.android.server.wm; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.AnimationAdapterProto.REMOTE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS; import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; @@ -26,7 +26,7 @@ import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index 6377a2169b34..5c6266a2f8c4 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; @@ -36,8 +36,8 @@ import android.util.TimeUtils; import android.view.Choreographer; import android.view.SurfaceControl; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index e24d185557e8..8a5e70f2e353 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -28,14 +28,14 @@ import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.os.UserHandle.USER_NULL; import static android.view.SurfaceControl.Transaction; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; import static com.android.server.wm.IdentifierProto.USER_ID; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; @@ -82,8 +82,8 @@ import android.window.IWindowContainerToken; import android.window.WindowContainerToken; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java index b75f886520e6..b9f67a590c2a 100644 --- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java +++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java @@ -19,7 +19,7 @@ package com.android.server.wm; import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT; import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR; @@ -39,7 +39,7 @@ import android.view.SurfaceControl.Builder; import android.view.SurfaceControl.Transaction; import android.view.animation.Animation; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.Animatable; import com.android.server.wm.SurfaceAnimator.AnimationType; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0b1d6bc0adfd..b33a8e9ef5df 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -84,22 +84,22 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN; import static com.android.server.LockGuard.INDEX_WINDOW; import static com.android.server.LockGuard.installLock; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; -import static com.android.server.wm.ProtoLogGroup.WM_ERROR; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -265,6 +265,8 @@ import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IShortcutService; import com.android.internal.policy.KeyInterceptionInfo; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.LatencyTracker; @@ -281,8 +283,6 @@ import com.android.server.input.InputManagerService; import com.android.server.policy.WindowManagerPolicy; import com.android.server.policy.WindowManagerPolicy.ScreenOffListener; import com.android.server.power.ShutdownThread; -import com.android.server.protolog.ProtoLogImpl; -import com.android.server.protolog.common.ProtoLog; import com.android.server.utils.PriorityDump; import com.android.server.wm.utils.DeviceConfigInterface; diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index bdecb8d99752..271d2b1a002f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -31,7 +31,7 @@ import android.view.Surface; import android.view.ViewDebug; import com.android.internal.os.ByteTransferPipe; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogImpl; import java.io.IOException; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index a58c5646858b..ab6e35b452a0 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,16 +1198,13 @@ 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) { - rootTask.handleAppDied(this); + // There may be a pausing activity that hasn't shown any window and was requested + // to be hidden. But pausing is also a visible state, it should be regarded as + // visible, so the caller can know the next activity should be resumed. + hasVisibleActivities |= rootTask.handleAppDied(this); } r.handleAppDied(); } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ab78e74b9e37..ebbd74aa7d1e 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -101,6 +101,14 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING_FREEFO import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME; import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.am.ActivityManagerService.MY_PID; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; @@ -116,14 +124,6 @@ import static com.android.server.wm.IdentifierProto.USER_ID; import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS; import static com.android.server.wm.MoveAnimationSpecProto.FROM; import static com.android.server.wm.MoveAnimationSpecProto.TO; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -236,10 +236,10 @@ import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.KeyInterceptionInfo; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ToBooleanFunction; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.LocalAnimationAdapter.AnimationSpec; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.utils.WmDisplayCutout; @@ -1535,10 +1535,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } InsetsState getInsetsState() { - final InsetsState insetsState = mToken.getFixedRotationTransformInsetsState(); - if (insetsState != null) { - return insetsState; - } return getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this); } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index d0101adaabad..16edb55939a3 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -31,13 +31,13 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_NONE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_DRAW; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_DRAW; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; @@ -76,8 +76,8 @@ import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index b89cdd32e132..9b40822c8ab5 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -21,8 +21,8 @@ import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW; import static android.view.SurfaceControl.METADATA_OWNER_UID; import static android.view.SurfaceControl.METADATA_WINDOW_TYPE; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; -import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC; +import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -40,7 +40,7 @@ import android.view.SurfaceControl; import android.view.WindowContentFrameStats; import android.view.WindowManager; -import com.android.server.protolog.common.ProtoLog; +import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2c1bb3ec51eb..f7cd37fb6748 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -23,10 +23,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; -import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; -import static com.android.server.wm.ProtoLogGroup.WM_ERROR; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS; +import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT; +import static com.android.internal.protolog.ProtoLogGroup.WM_ERROR; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; @@ -59,8 +59,8 @@ import android.view.SurfaceControl; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; -import com.android.server.protolog.common.ProtoLog; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index ba3dc607f6cc..e8b8bfce21a3 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -34,7 +34,7 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.util.TraceBuffer; import java.io.File; diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 74e2328105dc..b6633ced771b 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -49,6 +49,8 @@ namespace aidl = android::hardware::vibrator; namespace android { +static JavaVM* sJvm = nullptr; + static jmethodID sMethodIdOnComplete; static struct { @@ -228,6 +230,15 @@ bool isValidEffect(jlong effect) { return val >= *iter.begin() && val <= *std::prev(iter.end()); } +static void callVibrationOnComplete(jobject vibration) { + if (vibration == nullptr) { + return; + } + auto jniEnv = GetOrAttachJNIEnvironment(sJvm); + jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete); + jniEnv->DeleteGlobalRef(vibration); +} + static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) { aidl::CompositeEffect effect; effect.primitive = static_cast<aidl::CompositePrimitive>( @@ -273,18 +284,16 @@ static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controller return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE; } -static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) { - if (auto hal = getHal<aidl::IVibrator>()) { - auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr); - if (!status.isOk()) { - ALOGE("vibratorOn command failed: %s", status.toString8().string()); - } - } else { - Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); - if (retStatus != Status::OK) { - ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); - } +static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs, + jobject vibration) { + vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); + if (controller == nullptr) { + ALOGE("vibratorOn failed because controller was not initialized"); + return; } + jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); + auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; + controller->on(std::chrono::milliseconds(timeoutMs), callback); } static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { @@ -399,10 +408,11 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect return -1; } -static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jobjectArray composition, - jobject vibration) { - auto hal = getHal<aidl::IVibrator>(); - if (!hal) { +static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, + jobjectArray composition, jobject vibration) { + vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr); + if (controller == nullptr) { + ALOGE("vibratorPerformComposedEffect failed because controller was not initialized"); return; } size_t size = env->GetArrayLength(composition); @@ -411,14 +421,9 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jobje jobject element = env->GetObjectArrayElement(composition, i); effects.push_back(effectFromJavaPrimitive(env, element)); } - sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration); - - auto status = hal->call(&aidl::IVibrator::compose, effects, effectCallback); - if (!status.isOk()) { - if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) { - ALOGE("Failed to play haptic effect composition"); - } - } + jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration); + auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); }; + controller->performComposedEffect(effects, callback); } static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) { @@ -456,13 +461,13 @@ static const JNINativeMethod method_table[] = { {"vibratorInit", "()J", (void*)vibratorInit}, {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer}, {"vibratorExists", "(J)Z", (void*)vibratorExists}, - {"vibratorOn", "(J)V", (void*)vibratorOn}, + {"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn}, {"vibratorOff", "(J)V", (void*)vibratorOff}, {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude}, {"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J", (void*)vibratorPerformEffect}, {"vibratorPerformComposedEffect", - "([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" + "(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/" "VibratorService$Vibration;)V", (void*)vibratorPerformComposedEffect}, {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects}, @@ -472,7 +477,8 @@ static const JNINativeMethod method_table[] = { {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable}, }; -int register_android_server_VibratorService(JNIEnv *env) { +int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) { + sJvm = vm; sMethodIdOnComplete = GetMethodIDOrDie(env, FindClassOrDie(env, "com/android/server/VibratorService$Vibration"), diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 935dffe5021e..9751c46f93c9 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -421,6 +421,10 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO AutoMutex _l(mLock); mLocked.viewports = viewports; mLocked.pointerDisplayId = pointerDisplayId; + std::shared_ptr<PointerController> controller = mLocked.pointerController.lock(); + if (controller != nullptr) { + controller->onDisplayViewportsUpdated(mLocked.viewports); + } } // release lock mInputManager->getReader()->requestRefreshConfiguration( @@ -818,8 +822,8 @@ void NativeInputManager::updateInactivityTimeoutLocked() REQUIRES(mLock) { } bool lightsOut = mLocked.systemUiVisibility & ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN; - controller->setInactivityTimeout(lightsOut ? PointerController::InactivityTimeout::SHORT - : PointerController::InactivityTimeout::NORMAL); + controller->setInactivityTimeout(lightsOut ? InactivityTimeout::SHORT + : InactivityTimeout::NORMAL); } void NativeInputManager::setPointerSpeed(int32_t speed) { diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp index e904645bda8f..9e2bb45ab341 100644 --- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp +++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp @@ -314,31 +314,6 @@ static inline InputDescs openInputs(JNIEnv* env, const JniIds& jni, jobject shel return result; } -static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) { - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { - return 0; - } - return env; -} - -static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm) { - JNIEnv* env = GetJNIEnvironment(jvm); - if (!env) { - int result = jvm->AttachCurrentThread(&env, nullptr); - CHECK_EQ(result, JNI_OK) << "thread attach failed"; - struct VmDetacher { - VmDetacher(JavaVM* vm) : mVm(vm) {} - ~VmDetacher() { mVm->DetachCurrentThread(); } - - private: - JavaVM* const mVm; - }; - static thread_local VmDetacher detacher(jvm); - } - return env; -} - class PMSCDataLoader; struct OnTraceChanged { @@ -415,7 +390,7 @@ private: bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final { ALOGE("onPrepareImage: start."); - JNIEnv* env = GetOrAttachJNIEnvironment(mJvm); + JNIEnv* env = GetOrAttachJNIEnvironment(mJvm, JNI_VERSION_1_6); const auto& jni = jniIds(env); jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader, diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 6f24e3b580b7..5df1adafed5e 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -37,7 +37,7 @@ int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbMidiDevice(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_vr_VrManagerService(JNIEnv* env); -int register_android_server_VibratorService(JNIEnv* env); +int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env); int register_android_server_location_GnssLocationProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_TestNetworkService(JNIEnv* env); @@ -90,7 +90,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_UsbAlsaJackDetector(env); register_android_server_UsbHostManager(env); register_android_server_vr_VrManagerService(env); - register_android_server_VibratorService(env); + register_android_server_VibratorService(vm, env); register_android_server_SystemServer(env); register_android_server_location_GnssLocationProvider(env); register_android_server_connectivity_Vpn(env); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java new file mode 100644 index 000000000000..6fea2aaf728b --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -0,0 +1,1116 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.END_TAG; +import static org.xmlpull.v1.XmlPullParser.TEXT; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManager; +import android.app.admin.FactoryResetProtectionPolicy; +import android.app.admin.PasswordPolicy; +import android.graphics.Color; +import android.os.Bundle; +import android.os.PersistableBundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; +import android.util.Slog; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; +import com.android.internal.util.XmlUtils; +import com.android.server.pm.UserRestrictionsUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; + +class ActiveAdmin { + private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; + private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin"; + private static final String TAG_DISABLE_CAMERA = "disable-camera"; + private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; + private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search"; + private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING = + "disable-bt-contacts-sharing"; + private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture"; + private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management"; + private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time"; + private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users"; + private static final String TAG_IS_NETWORK_LOGGING_ENABLED = "is_network_logging_enabled"; + private static final String TAG_ACCOUNT_TYPE = "account-type"; + private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES = + "permitted-accessiblity-services"; + private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; + private static final String TAG_MANAGE_TRUST_AGENT_FEATURES = "manage-trust-agent-features"; + private static final String TAG_TRUST_AGENT_COMPONENT_OPTIONS = "trust-agent-component-options"; + private static final String TAG_TRUST_AGENT_COMPONENT = "component"; + private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date"; + private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout"; + private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list"; + private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec"; + private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy"; + private static final String TAG_PERMITTED_IMES = "permitted-imes"; + private static final String TAG_PERMITTED_NOTIFICATION_LISTENERS = + "permitted-notification-listeners"; + private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; + private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; + private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout"; + private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; + private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; + private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; + private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters"; + private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase"; + private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase"; + private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; + private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; + private static final String TAG_PASSWORD_QUALITY = "password-quality"; + private static final String TAG_POLICIES = "policies"; + private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS = + "cross-profile-widget-providers"; + private static final String TAG_PROVIDER = "provider"; + private static final String TAG_PACKAGE_LIST_ITEM = "item"; + private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; + private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; + private static final String TAG_DEFAULT_ENABLED_USER_RESTRICTIONS = + "default-enabled-user-restrictions"; + private static final String TAG_RESTRICTION = "restriction"; + private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; + private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; + private static final String TAG_PARENT_ADMIN = "parent-admin"; + private static final String TAG_ORGANIZATION_COLOR = "organization-color"; + private static final String TAG_ORGANIZATION_NAME = "organization-name"; + private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; + private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message"; + private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message"; + private static final String TAG_METERED_DATA_DISABLED_PACKAGES = + "metered_data_disabled_packages"; + private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES = + "cross-profile-calendar-packages"; + private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL = + "cross-profile-calendar-packages-null"; + private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages"; + private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = + "factory_reset_protection_policy"; + private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps"; + private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off"; + private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline"; + private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package"; + private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; + private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; + private static final String ATTR_VALUE = "value"; + private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; + private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; + + DeviceAdminInfo info; + + static final int DEF_PASSWORD_HISTORY_LENGTH = 0; + int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH; + + @NonNull + PasswordPolicy mPasswordPolicy = new PasswordPolicy(); + + @Nullable + FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null; + + static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; + long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; + + long strongAuthUnlockTimeout = 0; // admin doesn't participate by default + + static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0; + int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE; + + static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0; + long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT; + + static final long DEF_PASSWORD_EXPIRATION_DATE = 0; + long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; + + static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none + + int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; + + boolean encryptionRequested = false; + boolean testOnlyAdmin = false; + boolean disableCamera = false; + boolean disableCallerId = false; + boolean disableContactsSearch = false; + boolean disableBluetoothContactSharing = true; + boolean disableScreenCapture = false; + boolean requireAutoTime = false; + boolean forceEphemeralUsers = false; + boolean isNetworkLoggingEnabled = false; + boolean isLogoutEnabled = false; + + // one notification after enabling + one more after reboots + static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; + int numNetworkLoggingNotifications = 0; + long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch + + ActiveAdmin parentAdmin; + final boolean isParent; + + static class TrustAgentInfo { + public PersistableBundle options; + TrustAgentInfo(PersistableBundle bundle) { + options = bundle; + } + } + + // The list of packages which are not allowed to use metered data. + List<String> meteredDisabledPackages; + + final Set<String> accountTypesWithManagementDisabled = new ArraySet<>(); + + // The list of permitted accessibility services package namesas set by a profile + // or device owner. Null means all accessibility services are allowed, empty means + // none except system services are allowed. + List<String> permittedAccessiblityServices; + + // The list of permitted input methods package names as set by a profile or device owner. + // Null means all input methods are allowed, empty means none except system imes are + // allowed. + List<String> permittedInputMethods; + + // The list of packages allowed to use a NotificationListenerService to receive events for + // notifications from this user. Null means that all packages are allowed. Empty list means + // that only packages from the system are allowed. + List<String> permittedNotificationListeners; + + // List of package names to keep cached. + List<String> keepUninstalledPackages; + + // TODO: review implementation decisions with frameworks team + boolean specifiesGlobalProxy = false; + String globalProxySpec = null; + String globalProxyExclusionList = null; + + @NonNull + ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); + + List<String> crossProfileWidgetProviders; + + Bundle userRestrictions; + + // User restrictions that have already been enabled by default for this admin (either when + // setting the device or profile owner, or during a system update if one of those "enabled + // by default" restrictions is newly added). + final Set<String> defaultEnabledRestrictionsAlreadySet = new ArraySet<>(); + + // Support text provided by the admin to display to the user. + CharSequence shortSupportMessage = null; + CharSequence longSupportMessage = null; + + // Background color of confirm credentials screen. Default: teal. + static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B"); + int organizationColor = DEF_ORGANIZATION_COLOR; + + // Default title of confirm credentials screen + String organizationName = null; + + // Message for user switcher + String startUserSessionMessage = null; + String endUserSessionMessage = null; + + // The allow list of packages that can access cross profile calendar APIs. + // This allow list should be in default an empty list, which indicates that no package + // is allow listed. + List<String> mCrossProfileCalendarPackages = Collections.emptyList(); + + // The allow list of packages that the admin has enabled to be able to request consent from + // the user to communicate cross-profile. By default, no packages are allowed, which is + // represented as an empty list. + List<String> mCrossProfilePackages = Collections.emptyList(); + + // Whether the admin explicitly requires personal apps to be suspended + boolean mSuspendPersonalApps = false; + // Maximum time the profile owned by this admin can be off. + long mProfileMaximumTimeOffMillis = 0; + // Time by which the profile should be turned on according to System.currentTimeMillis(). + long mProfileOffDeadline = 0; + + public String mAlwaysOnVpnPackage; + public boolean mAlwaysOnVpnLockdown; + boolean mCommonCriteriaMode; + + ActiveAdmin(DeviceAdminInfo info, boolean isParent) { + this.info = info; + this.isParent = isParent; + } + + ActiveAdmin getParentActiveAdmin() { + Preconditions.checkState(!isParent); + + if (parentAdmin == null) { + parentAdmin = new ActiveAdmin(info, /* parent */ true); + } + return parentAdmin; + } + + boolean hasParentActiveAdmin() { + return parentAdmin != null; + } + + int getUid() { + return info.getActivityInfo().applicationInfo.uid; + } + + public UserHandle getUserHandle() { + return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); + } + + void writeToXml(XmlSerializer out) + throws IllegalArgumentException, IllegalStateException, IOException { + out.startTag(null, TAG_POLICIES); + info.writePoliciesToXml(out); + out.endTag(null, TAG_POLICIES); + if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) { + writeAttributeValueToXml( + out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality); + if (mPasswordPolicy.length != PasswordPolicy.DEF_MINIMUM_LENGTH) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LENGTH, mPasswordPolicy.length); + } + if (mPasswordPolicy.upperCase != PasswordPolicy.DEF_MINIMUM_UPPER_CASE) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_UPPERCASE, mPasswordPolicy.upperCase); + } + if (mPasswordPolicy.lowerCase != PasswordPolicy.DEF_MINIMUM_LOWER_CASE) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LOWERCASE, mPasswordPolicy.lowerCase); + } + if (mPasswordPolicy.letters != PasswordPolicy.DEF_MINIMUM_LETTERS) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_LETTERS, mPasswordPolicy.letters); + } + if (mPasswordPolicy.numeric != PasswordPolicy.DEF_MINIMUM_NUMERIC) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_NUMERIC, mPasswordPolicy.numeric); + } + if (mPasswordPolicy.symbols != PasswordPolicy.DEF_MINIMUM_SYMBOLS) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_SYMBOLS, mPasswordPolicy.symbols); + } + if (mPasswordPolicy.nonLetter > PasswordPolicy.DEF_MINIMUM_NON_LETTER) { + writeAttributeValueToXml( + out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter); + } + } + if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) { + writeAttributeValueToXml( + out, TAG_PASSWORD_HISTORY_LENGTH, passwordHistoryLength); + } + if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { + writeAttributeValueToXml( + out, TAG_MAX_TIME_TO_UNLOCK, maximumTimeToUnlock); + } + if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { + writeAttributeValueToXml( + out, TAG_STRONG_AUTH_UNLOCK_TIMEOUT, strongAuthUnlockTimeout); + } + if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { + writeAttributeValueToXml( + out, TAG_MAX_FAILED_PASSWORD_WIPE, maximumFailedPasswordsForWipe); + } + if (specifiesGlobalProxy) { + writeAttributeValueToXml( + out, TAG_SPECIFIES_GLOBAL_PROXY, specifiesGlobalProxy); + if (globalProxySpec != null) { + writeAttributeValueToXml(out, TAG_GLOBAL_PROXY_SPEC, globalProxySpec); + } + if (globalProxyExclusionList != null) { + writeAttributeValueToXml( + out, TAG_GLOBAL_PROXY_EXCLUSION_LIST, globalProxyExclusionList); + } + } + if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) { + writeAttributeValueToXml( + out, TAG_PASSWORD_EXPIRATION_TIMEOUT, passwordExpirationTimeout); + } + if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) { + writeAttributeValueToXml( + out, TAG_PASSWORD_EXPIRATION_DATE, passwordExpirationDate); + } + if (encryptionRequested) { + writeAttributeValueToXml( + out, TAG_ENCRYPTION_REQUESTED, encryptionRequested); + } + if (testOnlyAdmin) { + writeAttributeValueToXml( + out, TAG_TEST_ONLY_ADMIN, testOnlyAdmin); + } + if (disableCamera) { + writeAttributeValueToXml( + out, TAG_DISABLE_CAMERA, disableCamera); + } + if (disableCallerId) { + writeAttributeValueToXml( + out, TAG_DISABLE_CALLER_ID, disableCallerId); + } + if (disableContactsSearch) { + writeAttributeValueToXml( + out, TAG_DISABLE_CONTACTS_SEARCH, disableContactsSearch); + } + if (!disableBluetoothContactSharing) { + writeAttributeValueToXml( + out, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING, disableBluetoothContactSharing); + } + if (disableScreenCapture) { + writeAttributeValueToXml( + out, TAG_DISABLE_SCREEN_CAPTURE, disableScreenCapture); + } + if (requireAutoTime) { + writeAttributeValueToXml( + out, TAG_REQUIRE_AUTO_TIME, requireAutoTime); + } + if (forceEphemeralUsers) { + writeAttributeValueToXml( + out, TAG_FORCE_EPHEMERAL_USERS, forceEphemeralUsers); + } + if (isNetworkLoggingEnabled) { + out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); + out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled)); + out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS, + Integer.toString(numNetworkLoggingNotifications)); + out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION, + Long.toString(lastNetworkLoggingNotificationTimeMs)); + out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); + } + if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { + writeAttributeValueToXml( + out, TAG_DISABLE_KEYGUARD_FEATURES, disabledKeyguardFeatures); + } + if (!accountTypesWithManagementDisabled.isEmpty()) { + writeAttributeValuesToXml( + out, TAG_DISABLE_ACCOUNT_MANAGEMENT, TAG_ACCOUNT_TYPE, + accountTypesWithManagementDisabled); + } + if (!trustAgentInfos.isEmpty()) { + Set<Map.Entry<String, TrustAgentInfo>> set = trustAgentInfos.entrySet(); + out.startTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); + for (Map.Entry<String, TrustAgentInfo> entry : set) { + TrustAgentInfo trustAgentInfo = entry.getValue(); + out.startTag(null, TAG_TRUST_AGENT_COMPONENT); + out.attribute(null, ATTR_VALUE, entry.getKey()); + if (trustAgentInfo.options != null) { + out.startTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); + try { + trustAgentInfo.options.saveToXml(out); + } catch (XmlPullParserException e) { + Log.e(DevicePolicyManagerService.LOG_TAG, + "Failed to save TrustAgent options", e); + } + out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); + } + out.endTag(null, TAG_TRUST_AGENT_COMPONENT); + } + out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); + } + if (crossProfileWidgetProviders != null && !crossProfileWidgetProviders.isEmpty()) { + writeAttributeValuesToXml( + out, TAG_CROSS_PROFILE_WIDGET_PROVIDERS, TAG_PROVIDER, + crossProfileWidgetProviders); + } + writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, + permittedAccessiblityServices); + writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); + writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS, + permittedNotificationListeners); + writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); + writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages); + if (hasUserRestrictions()) { + UserRestrictionsUtils.writeRestrictions( + out, userRestrictions, TAG_USER_RESTRICTIONS); + } + if (!defaultEnabledRestrictionsAlreadySet.isEmpty()) { + writeAttributeValuesToXml(out, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS, + TAG_RESTRICTION, + defaultEnabledRestrictionsAlreadySet); + } + if (!TextUtils.isEmpty(shortSupportMessage)) { + writeTextToXml(out, TAG_SHORT_SUPPORT_MESSAGE, shortSupportMessage.toString()); + } + if (!TextUtils.isEmpty(longSupportMessage)) { + writeTextToXml(out, TAG_LONG_SUPPORT_MESSAGE, longSupportMessage.toString()); + } + if (parentAdmin != null) { + out.startTag(null, TAG_PARENT_ADMIN); + parentAdmin.writeToXml(out); + out.endTag(null, TAG_PARENT_ADMIN); + } + if (organizationColor != DEF_ORGANIZATION_COLOR) { + writeAttributeValueToXml(out, TAG_ORGANIZATION_COLOR, organizationColor); + } + if (organizationName != null) { + writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName); + } + if (isLogoutEnabled) { + writeAttributeValueToXml(out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled); + } + if (startUserSessionMessage != null) { + writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage); + } + if (endUserSessionMessage != null) { + writeTextToXml(out, TAG_END_USER_SESSION_MESSAGE, endUserSessionMessage); + } + if (mCrossProfileCalendarPackages == null) { + out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); + out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); + } else { + writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES, + mCrossProfileCalendarPackages); + } + writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages); + if (mFactoryResetProtectionPolicy != null) { + out.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + mFactoryResetProtectionPolicy.writeToXml(out); + out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); + } + if (mSuspendPersonalApps) { + writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps); + } + if (mProfileMaximumTimeOffMillis != 0) { + writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, + mProfileMaximumTimeOffMillis); + } + if (mProfileMaximumTimeOffMillis != 0) { + writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline); + } + if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage); + } + if (mAlwaysOnVpnLockdown) { + writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown); + } + if (mCommonCriteriaMode) { + writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode); + } + } + + void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { + out.startTag(null, tag); + out.text(text); + out.endTag(null, tag); + } + + void writePackageListToXml(XmlSerializer out, String outerTag, + List<String> packageList) + throws IllegalArgumentException, IllegalStateException, IOException { + if (packageList == null) { + return; + } + writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, String value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, value); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, int value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Integer.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, long value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Long.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value) + throws IOException { + out.startTag(null, tag); + out.attribute(null, ATTR_VALUE, Boolean.toString(value)); + out.endTag(null, tag); + } + + void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag, + @NonNull Collection<String> values) throws IOException { + out.startTag(null, outerTag); + for (String value : values) { + out.startTag(null, innerTag); + out.attribute(null, ATTR_VALUE, value); + out.endTag(null, innerTag); + } + out.endTag(null, outerTag); + } + + void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies) + throws XmlPullParserException, IOException { + int outerDepth = parser.getDepth(); + int type; + while ((type = parser.next()) != END_DOCUMENT + && (type != END_TAG || parser.getDepth() > outerDepth)) { + if (type == END_TAG || type == TEXT) { + continue; + } + String tag = parser.getName(); + if (TAG_POLICIES.equals(tag)) { + if (shouldOverridePolicies) { + Log.d(DevicePolicyManagerService.LOG_TAG, + "Overriding device admin policies from XML."); + info.readPoliciesFromXml(parser); + } + } else if (TAG_PASSWORD_QUALITY.equals(tag)) { + mPasswordPolicy.quality = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) { + mPasswordPolicy.length = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) { + passwordHistoryLength = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) { + mPasswordPolicy.upperCase = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) { + mPasswordPolicy.lowerCase = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) { + mPasswordPolicy.letters = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) { + mPasswordPolicy.numeric = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) { + mPasswordPolicy.symbols = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { + mPasswordPolicy.nonLetter = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { + maximumTimeToUnlock = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) { + strongAuthUnlockTimeout = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { + maximumFailedPasswordsForWipe = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) { + specifiesGlobalProxy = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) { + globalProxySpec = + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) { + globalProxyExclusionList = + parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) { + passwordExpirationTimeout = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) { + passwordExpirationDate = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { + encryptionRequested = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) { + testOnlyAdmin = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CAMERA.equals(tag)) { + disableCamera = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CALLER_ID.equals(tag)) { + disableCallerId = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) { + disableContactsSearch = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) { + disableBluetoothContactSharing = Boolean.parseBoolean(parser + .getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) { + disableScreenCapture = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) { + requireAutoTime = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) { + forceEphemeralUsers = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) { + isNetworkLoggingEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + lastNetworkLoggingNotificationTimeMs = Long.parseLong( + parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION)); + numNetworkLoggingNotifications = Integer.parseInt( + parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS)); + } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { + disabledKeyguardFeatures = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) { + readAttributeValues( + parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled); + } else if (TAG_MANAGE_TRUST_AGENT_FEATURES.equals(tag)) { + trustAgentInfos = getAllTrustAgentInfos(parser, tag); + } else if (TAG_CROSS_PROFILE_WIDGET_PROVIDERS.equals(tag)) { + crossProfileWidgetProviders = new ArrayList<>(); + readAttributeValues(parser, TAG_PROVIDER, crossProfileWidgetProviders); + } else if (TAG_PERMITTED_ACCESSIBILITY_SERVICES.equals(tag)) { + permittedAccessiblityServices = readPackageList(parser, tag); + } else if (TAG_PERMITTED_IMES.equals(tag)) { + permittedInputMethods = readPackageList(parser, tag); + } else if (TAG_PERMITTED_NOTIFICATION_LISTENERS.equals(tag)) { + permittedNotificationListeners = readPackageList(parser, tag); + } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { + keepUninstalledPackages = readPackageList(parser, tag); + } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) { + meteredDisabledPackages = readPackageList(parser, tag); + } else if (TAG_USER_RESTRICTIONS.equals(tag)) { + userRestrictions = UserRestrictionsUtils.readRestrictions(parser); + } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) { + readAttributeValues( + parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet); + } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + shortSupportMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading short support message"); + } + } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + longSupportMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading long support message"); + } + } else if (TAG_PARENT_ADMIN.equals(tag)) { + Preconditions.checkState(!isParent); + parentAdmin = new ActiveAdmin(info, /* parent */ true); + parentAdmin.readFromXml(parser, shouldOverridePolicies); + } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { + organizationColor = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ORGANIZATION_NAME.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + organizationName = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading organization name"); + } + } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) { + isLogoutEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + startUserSessionMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading start session message"); + } + } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + endUserSessionMessage = parser.getText(); + } else { + Log.w(DevicePolicyManagerService.LOG_TAG, + "Missing text when loading end session message"); + } + } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) { + mCrossProfileCalendarPackages = readPackageList(parser, tag); + } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) { + mCrossProfileCalendarPackages = null; + } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) { + mCrossProfilePackages = readPackageList(parser, tag); + } else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) { + mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml( + parser); + } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) { + mSuspendPersonalApps = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) { + mProfileMaximumTimeOffMillis = + Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) { + mProfileOffDeadline = + Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) { + mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE); + } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) { + mAlwaysOnVpnLockdown = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) { + mCommonCriteriaMode = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag); + XmlUtils.skipCurrentTag(parser); + } + } + } + + private List<String> readPackageList(XmlPullParser parser, + String tag) throws XmlPullParserException, IOException { + List<String> result = new ArrayList<String>(); + int outerDepth = parser.getDepth(); + int outerType; + while ((outerType = parser.next()) != XmlPullParser.END_DOCUMENT + && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) { + continue; + } + String outerTag = parser.getName(); + if (TAG_PACKAGE_LIST_ITEM.equals(outerTag)) { + String packageName = parser.getAttributeValue(null, ATTR_VALUE); + if (packageName != null) { + result.add(packageName); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Package name missing under " + outerTag); + } + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + outerTag); + } + } + return result; + } + + private void readAttributeValues( + XmlPullParser parser, String tag, Collection<String> result) + throws XmlPullParserException, IOException { + result.clear(); + int outerDepthDAM = parser.getDepth(); + int typeDAM; + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (tag.equals(tagDAM)) { + result.add(parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.e(DevicePolicyManagerService.LOG_TAG, + "Expected tag " + tag + " but found " + tagDAM); + } + } + } + + @NonNull + private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( + XmlPullParser parser, String tag) throws XmlPullParserException, IOException { + int outerDepthDAM = parser.getDepth(); + int typeDAM; + final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>(); + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (TAG_TRUST_AGENT_COMPONENT.equals(tagDAM)) { + final String component = parser.getAttributeValue(null, ATTR_VALUE); + final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag); + result.put(component, trustAgentInfo); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + tagDAM); + } + } + return result; + } + + private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag) + throws XmlPullParserException, IOException { + int outerDepthDAM = parser.getDepth(); + int typeDAM; + TrustAgentInfo result = new TrustAgentInfo(null); + while ((typeDAM = parser.next()) != END_DOCUMENT + && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { + if (typeDAM == END_TAG || typeDAM == TEXT) { + continue; + } + String tagDAM = parser.getName(); + if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) { + result.options = PersistableBundle.restoreFromXml(parser); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Unknown tag under " + tag + ": " + tagDAM); + } + } + return result; + } + + boolean hasUserRestrictions() { + return userRestrictions != null && userRestrictions.size() > 0; + } + + Bundle ensureUserRestrictions() { + if (userRestrictions == null) { + userRestrictions = new Bundle(); + } + return userRestrictions; + } + + public void transfer(DeviceAdminInfo deviceAdminInfo) { + if (hasParentActiveAdmin()) { + parentAdmin.info = deviceAdminInfo; + } + info = deviceAdminInfo; + } + + Bundle addSyntheticRestrictions(Bundle restrictions) { + if (disableCamera) { + restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); + } + if (requireAutoTime) { + restrictions.putBoolean(UserManager.DISALLOW_CONFIG_DATE_TIME, true); + } + return restrictions; + } + + static Bundle removeDeprecatedRestrictions(Bundle restrictions) { + for (String deprecatedRestriction: UserRestrictionsUtils.DEPRECATED_USER_RESTRICTIONS) { + restrictions.remove(deprecatedRestriction); + } + return restrictions; + } + + static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) { + Bundle result = new Bundle(); + for (String key : restrictions.keySet()) { + if (!restrictions.getBoolean(key)) { + continue; + } + if (filter.test(key)) { + result.putBoolean(key, true); + } + } + return result; + } + + Bundle getEffectiveRestrictions() { + return addSyntheticRestrictions( + removeDeprecatedRestrictions(new Bundle(ensureUserRestrictions()))); + } + + Bundle getLocalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isLocal(adminType, key)); + } + + Bundle getGlobalUserRestrictions(int adminType) { + return filterRestrictions(getEffectiveRestrictions(), + key -> UserRestrictionsUtils.isGlobal(adminType, key)); + } + + void dump(IndentingPrintWriter pw) { + pw.print("uid="); + pw.println(getUid()); + + pw.print("testOnlyAdmin="); + pw.println(testOnlyAdmin); + + pw.println("policies:"); + ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); + if (pols != null) { + pw.increaseIndent(); + for (int i = 0; i < pols.size(); i++) { + pw.println(pols.get(i).tag); + } + pw.decreaseIndent(); + } + + pw.print("passwordQuality=0x"); + pw.println(Integer.toHexString(mPasswordPolicy.quality)); + + pw.print("minimumPasswordLength="); + pw.println(mPasswordPolicy.length); + + pw.print("passwordHistoryLength="); + pw.println(passwordHistoryLength); + + pw.print("minimumPasswordUpperCase="); + pw.println(mPasswordPolicy.upperCase); + + pw.print("minimumPasswordLowerCase="); + pw.println(mPasswordPolicy.lowerCase); + + pw.print("minimumPasswordLetters="); + pw.println(mPasswordPolicy.letters); + + pw.print("minimumPasswordNumeric="); + pw.println(mPasswordPolicy.numeric); + + pw.print("minimumPasswordSymbols="); + pw.println(mPasswordPolicy.symbols); + + pw.print("minimumPasswordNonLetter="); + pw.println(mPasswordPolicy.nonLetter); + + pw.print("maximumTimeToUnlock="); + pw.println(maximumTimeToUnlock); + + pw.print("strongAuthUnlockTimeout="); + pw.println(strongAuthUnlockTimeout); + + pw.print("maximumFailedPasswordsForWipe="); + pw.println(maximumFailedPasswordsForWipe); + + pw.print("specifiesGlobalProxy="); + pw.println(specifiesGlobalProxy); + + pw.print("passwordExpirationTimeout="); + pw.println(passwordExpirationTimeout); + + pw.print("passwordExpirationDate="); + pw.println(passwordExpirationDate); + + if (globalProxySpec != null) { + pw.print("globalProxySpec="); + pw.println(globalProxySpec); + } + if (globalProxyExclusionList != null) { + pw.print("globalProxyEclusionList="); + pw.println(globalProxyExclusionList); + } + pw.print("encryptionRequested="); + pw.println(encryptionRequested); + + pw.print("disableCamera="); + pw.println(disableCamera); + + pw.print("disableCallerId="); + pw.println(disableCallerId); + + pw.print("disableContactsSearch="); + pw.println(disableContactsSearch); + + pw.print("disableBluetoothContactSharing="); + pw.println(disableBluetoothContactSharing); + + pw.print("disableScreenCapture="); + pw.println(disableScreenCapture); + + pw.print("requireAutoTime="); + pw.println(requireAutoTime); + + pw.print("forceEphemeralUsers="); + pw.println(forceEphemeralUsers); + + pw.print("isNetworkLoggingEnabled="); + pw.println(isNetworkLoggingEnabled); + + pw.print("disabledKeyguardFeatures="); + pw.println(disabledKeyguardFeatures); + + pw.print("crossProfileWidgetProviders="); + pw.println(crossProfileWidgetProviders); + + if (permittedAccessiblityServices != null) { + pw.print("permittedAccessibilityServices="); + pw.println(permittedAccessiblityServices); + } + + if (permittedInputMethods != null) { + pw.print("permittedInputMethods="); + pw.println(permittedInputMethods); + } + + if (permittedNotificationListeners != null) { + pw.print("permittedNotificationListeners="); + pw.println(permittedNotificationListeners); + } + + if (keepUninstalledPackages != null) { + pw.print("keepUninstalledPackages="); + pw.println(keepUninstalledPackages); + } + + pw.print("organizationColor="); + pw.println(organizationColor); + + if (organizationName != null) { + pw.print("organizationName="); + pw.println(organizationName); + } + + pw.println("userRestrictions:"); + UserRestrictionsUtils.dumpRestrictions(pw, " ", userRestrictions); + + pw.print("defaultEnabledRestrictionsAlreadySet="); + pw.println(defaultEnabledRestrictionsAlreadySet); + + pw.print("isParent="); + pw.println(isParent); + + if (parentAdmin != null) { + pw.println("parentAdmin:"); + pw.increaseIndent(); + parentAdmin.dump(pw); + pw.decreaseIndent(); + } + + if (mCrossProfileCalendarPackages != null) { + pw.print("mCrossProfileCalendarPackages="); + pw.println(mCrossProfileCalendarPackages); + } + + pw.print("mCrossProfilePackages="); + pw.println(mCrossProfilePackages); + + pw.print("mSuspendPersonalApps="); + pw.println(mSuspendPersonalApps); + + pw.print("mProfileMaximumTimeOffMillis="); + pw.println(mProfileMaximumTimeOffMillis); + + pw.print("mProfileOffDeadline="); + pw.println(mProfileOffDeadline); + + pw.print("mAlwaysOnVpnPackage="); + pw.println(mAlwaysOnVpnPackage); + + pw.print("mAlwaysOnVpnLockdown="); + pw.println(mAlwaysOnVpnLockdown); + + pw.print("mCommonCriteriaMode="); + pw.println(mCommonCriteriaMode); + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java new file mode 100644 index 000000000000..130cfd50b203 --- /dev/null +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.devicepolicy; + +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.os.FileUtils; +import android.os.PersistableBundle; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.JournaledFile; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +class DevicePolicyData { + private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate"; + private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; + private static final String TAG_LOCK_TASK_FEATURES = "lock-task-features"; + private static final String TAG_STATUS_BAR = "statusbar"; + private static final String TAG_APPS_SUSPENDED = "apps-suspended"; + private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen"; + private static final String TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT = + "do-not-ask-credentials-on-boot"; + private static final String TAG_AFFILIATION_ID = "affiliation-id"; + private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval"; + private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request"; + private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval"; + private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending"; + private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set"; + private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert"; + private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle"; + private static final String TAG_PASSWORD_VALIDITY = "password-validity"; + private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token"; + private static final String TAG_PROTECTED_PACKAGES = "protected-packages"; + private static final String ATTR_VALUE = "value"; + private static final String ATTR_ALIAS = "alias"; + private static final String ATTR_ID = "id"; + private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; + private static final String ATTR_NAME = "name"; + private static final String ATTR_DISABLED = "disabled"; + private static final String ATTR_SETUP_COMPLETE = "setup-complete"; + private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; + private static final String ATTR_PERMISSION_POLICY = "permission-policy"; + private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED = + "device-provisioning-config-applied"; + private static final String ATTR_DEVICE_PAIRED = "device-paired"; + + int mFailedPasswordAttempts = 0; + boolean mPasswordValidAtLastCheckpoint = true; + + int mUserHandle; + int mPasswordOwner = -1; + long mLastMaximumTimeToLock = -1; + boolean mUserSetupComplete = false; + boolean mPaired = false; + int mUserProvisioningState; + int mPermissionPolicy; + + boolean mDeviceProvisioningConfigApplied = false; + + final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); + final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); + final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); + + // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. + final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>(); + + // This is the list of component allowed to start lock task mode. + List<String> mLockTaskPackages = new ArrayList<>(); + + // List of packages protected by device owner + List<String> mUserControlDisabledPackages = new ArrayList<>(); + + // Bitfield of feature flags to be enabled during LockTask mode. + // We default on the power button menu, in order to be consistent with pre-P behaviour. + int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; + + boolean mStatusBarDisabled = false; + + ComponentName mRestrictionsProvider; + + // Map of delegate package to delegation scopes + final ArrayMap<String, List<String>> mDelegationMap = new ArrayMap<>(); + + boolean mDoNotAskCredentialsOnBoot = false; + + Set<String> mAffiliationIds = new ArraySet<>(); + + long mLastSecurityLogRetrievalTime = -1; + + long mLastBugReportRequestTime = -1; + + long mLastNetworkLogsRetrievalTime = -1; + + boolean mCurrentInputMethodSet = false; + + boolean mSecondaryLockscreenEnabled = false; + + // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. + Set<String> mOwnerInstalledCaCerts = new ArraySet<>(); + + // Used for initialization of users created by createAndManageUser. + boolean mAdminBroadcastPending = false; + PersistableBundle mInitBundle = null; + + long mPasswordTokenHandle = 0; + + // Whether user's apps are suspended. This flag should only be written AFTER all the needed + // apps were suspended or unsuspended. + boolean mAppsSuspended = false; + + DevicePolicyData(int userHandle) { + mUserHandle = userHandle; + } + + /** + * Serializes DevicePolicyData object as XML. + */ + static boolean store(DevicePolicyData policyData, JournaledFile file, boolean isFdeDevice) { + FileOutputStream stream = null; + try { + stream = new FileOutputStream(file.chooseForWrite(), false); + XmlSerializer out = new FastXmlSerializer(); + out.setOutput(stream, StandardCharsets.UTF_8.name()); + out.startDocument(null, true); + + out.startTag(null, "policies"); + if (policyData.mRestrictionsProvider != null) { + out.attribute(null, ATTR_PERMISSION_PROVIDER, + policyData.mRestrictionsProvider.flattenToString()); + } + if (policyData.mUserSetupComplete) { + out.attribute(null, ATTR_SETUP_COMPLETE, + Boolean.toString(true)); + } + if (policyData.mPaired) { + out.attribute(null, ATTR_DEVICE_PAIRED, + Boolean.toString(true)); + } + if (policyData.mDeviceProvisioningConfigApplied) { + out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, + Boolean.toString(true)); + } + if (policyData.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { + out.attribute(null, ATTR_PROVISIONING_STATE, + Integer.toString(policyData.mUserProvisioningState)); + } + if (policyData.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { + out.attribute(null, ATTR_PERMISSION_POLICY, + Integer.toString(policyData.mPermissionPolicy)); + } + + // Serialize delegations. + for (int i = 0; i < policyData.mDelegationMap.size(); ++i) { + final String delegatePackage = policyData.mDelegationMap.keyAt(i); + final List<String> scopes = policyData.mDelegationMap.valueAt(i); + + // Every "delegation" tag serializes the information of one delegate-scope pair. + for (String scope : scopes) { + out.startTag(null, "delegation"); + out.attribute(null, "delegatePackage", delegatePackage); + out.attribute(null, "scope", scope); + out.endTag(null, "delegation"); + } + } + + final int n = policyData.mAdminList.size(); + for (int i = 0; i < n; i++) { + ActiveAdmin ap = policyData.mAdminList.get(i); + if (ap != null) { + out.startTag(null, "admin"); + out.attribute(null, "name", ap.info.getComponent().flattenToString()); + ap.writeToXml(out); + out.endTag(null, "admin"); + } + } + + if (policyData.mPasswordOwner >= 0) { + out.startTag(null, "password-owner"); + out.attribute(null, "value", Integer.toString(policyData.mPasswordOwner)); + out.endTag(null, "password-owner"); + } + + if (policyData.mFailedPasswordAttempts != 0) { + out.startTag(null, "failed-password-attempts"); + out.attribute(null, "value", Integer.toString(policyData.mFailedPasswordAttempts)); + out.endTag(null, "failed-password-attempts"); + } + + // For FDE devices only, we save this flag so we can report on password sufficiency + // before the user enters their password for the first time after a reboot. For + // security reasons, we don't want to store the full set of active password metrics. + if (isFdeDevice) { + out.startTag(null, TAG_PASSWORD_VALIDITY); + out.attribute(null, ATTR_VALUE, + Boolean.toString(policyData.mPasswordValidAtLastCheckpoint)); + out.endTag(null, TAG_PASSWORD_VALIDITY); + } + + for (int i = 0; i < policyData.mAcceptedCaCertificates.size(); i++) { + out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + out.attribute(null, ATTR_NAME, policyData.mAcceptedCaCertificates.valueAt(i)); + out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES); + } + + for (int i = 0; i < policyData.mLockTaskPackages.size(); i++) { + String component = policyData.mLockTaskPackages.get(i); + out.startTag(null, TAG_LOCK_TASK_COMPONENTS); + out.attribute(null, "name", component); + out.endTag(null, TAG_LOCK_TASK_COMPONENTS); + } + + if (policyData.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) { + out.startTag(null, TAG_LOCK_TASK_FEATURES); + out.attribute(null, ATTR_VALUE, Integer.toString(policyData.mLockTaskFeatures)); + out.endTag(null, TAG_LOCK_TASK_FEATURES); + } + + if (policyData.mSecondaryLockscreenEnabled) { + out.startTag(null, TAG_SECONDARY_LOCK_SCREEN); + out.attribute(null, ATTR_VALUE, Boolean.toString(true)); + out.endTag(null, TAG_SECONDARY_LOCK_SCREEN); + } + + if (policyData.mStatusBarDisabled) { + out.startTag(null, TAG_STATUS_BAR); + out.attribute(null, ATTR_DISABLED, Boolean.toString(policyData.mStatusBarDisabled)); + out.endTag(null, TAG_STATUS_BAR); + } + + if (policyData.mDoNotAskCredentialsOnBoot) { + out.startTag(null, TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT); + out.endTag(null, TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT); + } + + for (String id : policyData.mAffiliationIds) { + out.startTag(null, TAG_AFFILIATION_ID); + out.attribute(null, ATTR_ID, id); + out.endTag(null, TAG_AFFILIATION_ID); + } + + if (policyData.mLastSecurityLogRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastSecurityLogRetrievalTime)); + out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); + } + + if (policyData.mLastBugReportRequestTime >= 0) { + out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastBugReportRequestTime)); + out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST); + } + + if (policyData.mLastNetworkLogsRetrievalTime >= 0) { + out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mLastNetworkLogsRetrievalTime)); + out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); + } + + if (policyData.mAdminBroadcastPending) { + out.startTag(null, TAG_ADMIN_BROADCAST_PENDING); + out.attribute(null, ATTR_VALUE, + Boolean.toString(policyData.mAdminBroadcastPending)); + out.endTag(null, TAG_ADMIN_BROADCAST_PENDING); + } + + if (policyData.mInitBundle != null) { + out.startTag(null, TAG_INITIALIZATION_BUNDLE); + policyData.mInitBundle.saveToXml(out); + out.endTag(null, TAG_INITIALIZATION_BUNDLE); + } + + if (policyData.mPasswordTokenHandle != 0) { + out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE); + out.attribute(null, ATTR_VALUE, + Long.toString(policyData.mPasswordTokenHandle)); + out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE); + } + + if (policyData.mCurrentInputMethodSet) { + out.startTag(null, TAG_CURRENT_INPUT_METHOD_SET); + out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET); + } + + for (final String cert : policyData.mOwnerInstalledCaCerts) { + out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT); + out.attribute(null, ATTR_ALIAS, cert); + out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT); + } + + for (int i = 0, size = policyData.mUserControlDisabledPackages.size(); i < size; i++) { + String packageName = policyData.mUserControlDisabledPackages.get(i); + out.startTag(null, TAG_PROTECTED_PACKAGES); + out.attribute(null, ATTR_NAME, packageName); + out.endTag(null, TAG_PROTECTED_PACKAGES); + } + + if (policyData.mAppsSuspended) { + out.startTag(null, TAG_APPS_SUSPENDED); + out.attribute(null, ATTR_VALUE, Boolean.toString(policyData.mAppsSuspended)); + out.endTag(null, TAG_APPS_SUSPENDED); + } + + out.endTag(null, "policies"); + + out.endDocument(); + stream.flush(); + FileUtils.sync(stream); + stream.close(); + file.commit(); + return true; + } catch (XmlPullParserException | IOException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "failed writing file", e); + try { + if (stream != null) { + stream.close(); + } + } catch (IOException ex) { + // Ignore + } + file.rollback(); + return false; + } + } + + /** + * @param adminInfoSupplier function that queries DeviceAdminInfo from PackageManager + * @param ownerComponent device or profile owner component if any. + */ + static boolean load(DevicePolicyData policy, boolean isFdeDevice, JournaledFile journaledFile, + Function<ComponentName, DeviceAdminInfo> adminInfoSupplier, + ComponentName ownerComponent) { + FileInputStream stream = null; + File file = journaledFile.chooseForRead(); + boolean needsRewrite = false; + try { + stream = new FileInputStream(file); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(stream, StandardCharsets.UTF_8.name()); + + int type; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && type != XmlPullParser.START_TAG) { + } + String tag = parser.getName(); + if (!"policies".equals(tag)) { + throw new XmlPullParserException( + "Settings do not start with policies tag: found " + tag); + } + + // Extract the permission provider component name if available + String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER); + if (permissionProvider != null) { + policy.mRestrictionsProvider = + ComponentName.unflattenFromString(permissionProvider); + } + String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE); + if (Boolean.toString(true).equals(userSetupComplete)) { + policy.mUserSetupComplete = true; + } + String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED); + if (Boolean.toString(true).equals(paired)) { + policy.mPaired = true; + } + String deviceProvisioningConfigApplied = parser.getAttributeValue(null, + ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED); + if (Boolean.toString(true).equals(deviceProvisioningConfigApplied)) { + policy.mDeviceProvisioningConfigApplied = true; + } + String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); + if (!TextUtils.isEmpty(provisioningState)) { + policy.mUserProvisioningState = Integer.parseInt(provisioningState); + } + String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); + if (!TextUtils.isEmpty(permissionPolicy)) { + policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); + } + + parser.next(); + int outerDepth = parser.getDepth(); + policy.mLockTaskPackages.clear(); + policy.mAdminList.clear(); + policy.mAdminMap.clear(); + policy.mAffiliationIds.clear(); + policy.mOwnerInstalledCaCerts.clear(); + policy.mUserControlDisabledPackages.clear(); + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + tag = parser.getName(); + if ("admin".equals(tag)) { + String name = parser.getAttributeValue(null, "name"); + try { + DeviceAdminInfo dai = adminInfoSupplier.apply( + ComponentName.unflattenFromString(name)); + + if (dai != null) { + // b/123415062: If DA, overwrite with the stored policies that were + // agreed by the user to prevent apps from sneaking additional policies + // into updates. + boolean overwritePolicies = !dai.getComponent().equals(ownerComponent); + ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); + ap.readFromXml(parser, overwritePolicies); + policy.mAdminMap.put(ap.info.getComponent(), ap); + } + } catch (RuntimeException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, + "Failed loading admin " + name, e); + } + } else if ("delegation".equals(tag)) { + // Parse delegation info. + final String delegatePackage = parser.getAttributeValue(null, + "delegatePackage"); + final String scope = parser.getAttributeValue(null, "scope"); + + // Get a reference to the scopes list for the delegatePackage. + List<String> scopes = policy.mDelegationMap.get(delegatePackage); + // Or make a new list if none was found. + if (scopes == null) { + scopes = new ArrayList<>(); + policy.mDelegationMap.put(delegatePackage, scopes); + } + // Add the new scope to the list of delegatePackage if it's not already there. + if (!scopes.contains(scope)) { + scopes.add(scope); + } + } else if ("failed-password-attempts".equals(tag)) { + policy.mFailedPasswordAttempts = Integer.parseInt( + parser.getAttributeValue(null, "value")); + } else if ("password-owner".equals(tag)) { + policy.mPasswordOwner = Integer.parseInt( + parser.getAttributeValue(null, "value")); + } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { + policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); + } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { + policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); + } else if (TAG_LOCK_TASK_FEATURES.equals(tag)) { + policy.mLockTaskFeatures = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) { + policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_STATUS_BAR.equals(tag)) { + policy.mStatusBarDisabled = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_DISABLED)); + } else if (TAG_DO_NOT_ASK_CREDENTIALS_ON_BOOT.equals(tag)) { + policy.mDoNotAskCredentialsOnBoot = true; + } else if (TAG_AFFILIATION_ID.equals(tag)) { + policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID)); + } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) { + policy.mLastSecurityLogRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) { + policy.mLastBugReportRequestTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) { + policy.mLastNetworkLogsRetrievalTime = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { + String pending = parser.getAttributeValue(null, ATTR_VALUE); + policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); + } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { + policy.mInitBundle = PersistableBundle.restoreFromXml(parser); + } else if ("active-password".equals(tag)) { + // Remove password metrics from saved settings, as we no longer wish to store + // these on disk + needsRewrite = true; + } else if (TAG_PASSWORD_VALIDITY.equals(tag)) { + if (isFdeDevice) { + // This flag is only used for FDE devices + policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); + } + } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) { + policy.mPasswordTokenHandle = Long.parseLong( + parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) { + policy.mCurrentInputMethodSet = true; + } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) { + policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS)); + } else if (TAG_PROTECTED_PACKAGES.equals(tag)) { + policy.mUserControlDisabledPackages.add( + parser.getAttributeValue(null, ATTR_NAME)); + } else if (TAG_APPS_SUSPENDED.equals(tag)) { + policy.mAppsSuspended = + Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE)); + } else { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown tag: " + tag); + XmlUtils.skipCurrentTag(parser); + } + } + } catch (FileNotFoundException e) { + // Don't be noisy, this is normal if we haven't defined any policies. + } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException + | IndexOutOfBoundsException e) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "failed parsing " + file, e); + } + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + // Ignore + } + + // Generate a list of admins from the admin map + policy.mAdminList.addAll(policy.mAdminMap.values()); + return needsRewrite; + } + + void validatePasswordOwner() { + if (mPasswordOwner >= 0) { + boolean haveOwner = false; + for (int i = mAdminList.size() - 1; i >= 0; i--) { + if (mAdminList.get(i).getUid() == mPasswordOwner) { + haveOwner = true; + break; + } + } + if (!haveOwner) { + Slog.w(DevicePolicyManagerService.LOG_TAG, "Previous password owner " + + mPasswordOwner + " no longer active; disabling"); + mPasswordOwner = -1; + } + } + } +} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9a2bef85860f..cafd56e5198b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -106,10 +106,6 @@ import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.A import static com.android.server.devicepolicy.TransferOwnershipMetadataManager.ADMIN_TYPE_PROFILE_OWNER; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.TEXT; - import android.Manifest.permission; import android.accessibilityservice.AccessibilityServiceInfo; import android.accounts.Account; @@ -189,7 +185,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.Color; import android.location.LocationManager; import android.media.AudioManager; import android.media.IAudioService; @@ -204,7 +199,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -248,7 +242,6 @@ import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; import android.text.TextUtils; import android.text.format.DateUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.Log; @@ -280,7 +273,6 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.JournaledFile; import com.android.internal.util.Preconditions; import com.android.internal.util.StatLogger; -import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.LockscreenCredential; @@ -290,8 +282,7 @@ import com.android.server.LockGuard; import com.android.server.PersistentDataBlockManagerInternal; import com.android.server.SystemServerInitThreadPool; import com.android.server.SystemService; -import com.android.server.SystemService.TargetUser; -import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; +import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.RestrictionsSet; @@ -328,7 +319,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -350,55 +340,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String TRANSFER_OWNERSHIP_PARAMETERS_XML = "transfer-ownership-parameters.xml"; - private static final String TAG_ACCEPTED_CA_CERTIFICATES = "accepted-ca-certificate"; - - private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component"; - - private static final String TAG_LOCK_TASK_FEATURES = "lock-task-features"; - - private static final String TAG_STATUS_BAR = "statusbar"; - - private static final String ATTR_DISABLED = "disabled"; - - private static final String ATTR_NAME = "name"; - - private static final String DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML = - "do-not-ask-credentials-on-boot"; - - private static final String TAG_AFFILIATION_ID = "affiliation-id"; - - private static final String TAG_LAST_SECURITY_LOG_RETRIEVAL = "last-security-log-retrieval"; - - private static final String TAG_LAST_BUG_REPORT_REQUEST = "last-bug-report-request"; - - private static final String TAG_LAST_NETWORK_LOG_RETRIEVAL = "last-network-log-retrieval"; - - private static final String TAG_ADMIN_BROADCAST_PENDING = "admin-broadcast-pending"; - - private static final String TAG_CURRENT_INPUT_METHOD_SET = "current-ime-set"; - - private static final String TAG_OWNER_INSTALLED_CA_CERT = "owner-installed-ca-cert"; - - private static final String ATTR_ID = "id"; - - private static final String ATTR_VALUE = "value"; - - private static final String ATTR_ALIAS = "alias"; - - private static final String TAG_INITIALIZATION_BUNDLE = "initialization-bundle"; - - private static final String TAG_PASSWORD_TOKEN_HANDLE = "password-token"; - - private static final String TAG_PASSWORD_VALIDITY = "password-validity"; - private static final String TAG_TRANSFER_OWNERSHIP_BUNDLE = "transfer-ownership-bundle"; - private static final String TAG_PROTECTED_PACKAGES = "protected-packages"; - - private static final String TAG_SECONDARY_LOCK_SCREEN = "secondary-lock-screen"; - - private static final String TAG_APPS_SUSPENDED = "apps-suspended"; - private static final int REQUEST_EXPIRE_PASSWORD = 5571; private static final int REQUEST_PROFILE_OFF_DEADLINE = 5572; @@ -423,17 +366,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { static final String ACTION_PROFILE_OFF_DEADLINE = "com.android.server.ACTION_PROFILE_OFF_DEADLINE"; - private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; - private static final String ATTR_SETUP_COMPLETE = "setup-complete"; - private static final String ATTR_PROVISIONING_STATE = "provisioning-state"; - private static final String ATTR_PERMISSION_POLICY = "permission-policy"; - private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED = - "device-provisioning-config-applied"; - private static final String ATTR_DEVICE_PAIRED = "device-paired"; - private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer"; - private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER - = "application-restrictions-manager"; - private static final String CALLED_FROM_PARENT = "calledFromParent"; private static final String NOT_CALLED_FROM_PARENT = "notCalledFromParent"; @@ -488,7 +420,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final Set<String> SYSTEM_SETTINGS_WHITELIST; private static final Set<Integer> DA_DISALLOWED_POLICIES; // A collection of user restrictions that are deprecated and should simply be ignored. - private static final Set<String> DEPRECATED_USER_RESTRICTIONS; private static final String AB_DEVICE_KEY = "ro.build.ab_update"; static { @@ -532,10 +463,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - - DEPRECATED_USER_RESTRICTIONS = Sets.newHashSet( - UserManager.DISALLOW_ADD_MANAGED_PROFILE, - UserManager.DISALLOW_REMOVE_MANAGED_PROFILE); } /** @@ -791,76 +718,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - public static class DevicePolicyData { - int mFailedPasswordAttempts = 0; - boolean mPasswordValidAtLastCheckpoint = true; - - int mUserHandle; - int mPasswordOwner = -1; - long mLastMaximumTimeToLock = -1; - boolean mUserSetupComplete = false; - boolean mPaired = false; - int mUserProvisioningState; - int mPermissionPolicy; - - boolean mDeviceProvisioningConfigApplied = false; - - final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>(); - final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); - final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); - - // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. - final ArraySet<String> mAcceptedCaCertificates = new ArraySet<>(); - - // This is the list of component allowed to start lock task mode. - List<String> mLockTaskPackages = new ArrayList<>(); - - // List of packages protected by device owner - List<String> mUserControlDisabledPackages = new ArrayList<>(); - - // Bitfield of feature flags to be enabled during LockTask mode. - // We default on the power button menu, in order to be consistent with pre-P behaviour. - int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; - - boolean mStatusBarDisabled = false; - - ComponentName mRestrictionsProvider; - - // Map of delegate package to delegation scopes - final ArrayMap<String, List<String>> mDelegationMap = new ArrayMap<>(); - - boolean doNotAskCredentialsOnBoot = false; - - Set<String> mAffiliationIds = new ArraySet<>(); - - long mLastSecurityLogRetrievalTime = -1; - - long mLastBugReportRequestTime = -1; - - long mLastNetworkLogsRetrievalTime = -1; - - boolean mCurrentInputMethodSet = false; - - boolean mSecondaryLockscreenEnabled = false; - - // TODO(b/35385311): Keep track of metadata in TrustedCertificateStore instead. - Set<String> mOwnerInstalledCaCerts = new ArraySet<>(); - - // Used for initialization of users created by createAndManageUser. - boolean mAdminBroadcastPending = false; - PersistableBundle mInitBundle = null; - - long mPasswordTokenHandle = 0; - - // Whether user's apps are suspended. This flag should only be written AFTER all the needed - // apps were suspended or unsuspended. - boolean mAppsSuspended = false; - - public DevicePolicyData(int userHandle) { - mUserHandle = userHandle; - } - } - @GuardedBy("getLockObject()") final SparseArray<DevicePolicyData> mUserData = new SparseArray<>(); @@ -1045,1002 +902,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - static class ActiveAdmin { - private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; - private static final String TAG_TEST_ONLY_ADMIN = "test-only-admin"; - private static final String TAG_DISABLE_CAMERA = "disable-camera"; - private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; - private static final String TAG_DISABLE_CONTACTS_SEARCH = "disable-contacts-search"; - private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING - = "disable-bt-contacts-sharing"; - private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture"; - private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management"; - private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time"; - private static final String TAG_FORCE_EPHEMERAL_USERS = "force_ephemeral_users"; - private static final String TAG_IS_NETWORK_LOGGING_ENABLED = "is_network_logging_enabled"; - private static final String TAG_ACCOUNT_TYPE = "account-type"; - private static final String TAG_PERMITTED_ACCESSIBILITY_SERVICES - = "permitted-accessiblity-services"; - private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; - private static final String TAG_MANAGE_TRUST_AGENT_FEATURES = "manage-trust-agent-features"; - private static final String TAG_TRUST_AGENT_COMPONENT_OPTIONS = "trust-agent-component-options"; - private static final String TAG_TRUST_AGENT_COMPONENT = "component"; - private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date"; - private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout"; - private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list"; - private static final String TAG_GLOBAL_PROXY_SPEC = "global-proxy-spec"; - private static final String TAG_SPECIFIES_GLOBAL_PROXY = "specifies-global-proxy"; - private static final String TAG_PERMITTED_IMES = "permitted-imes"; - private static final String TAG_PERMITTED_NOTIFICATION_LISTENERS = - "permitted-notification-listeners"; - private static final String TAG_MAX_FAILED_PASSWORD_WIPE = "max-failed-password-wipe"; - private static final String TAG_MAX_TIME_TO_UNLOCK = "max-time-to-unlock"; - private static final String TAG_STRONG_AUTH_UNLOCK_TIMEOUT = "strong-auth-unlock-timeout"; - private static final String TAG_MIN_PASSWORD_NONLETTER = "min-password-nonletter"; - private static final String TAG_MIN_PASSWORD_SYMBOLS = "min-password-symbols"; - private static final String TAG_MIN_PASSWORD_NUMERIC = "min-password-numeric"; - private static final String TAG_MIN_PASSWORD_LETTERS = "min-password-letters"; - private static final String TAG_MIN_PASSWORD_LOWERCASE = "min-password-lowercase"; - private static final String TAG_MIN_PASSWORD_UPPERCASE = "min-password-uppercase"; - private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length"; - private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length"; - private static final String ATTR_VALUE = "value"; - private static final String TAG_PASSWORD_QUALITY = "password-quality"; - private static final String TAG_POLICIES = "policies"; - private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS = - "cross-profile-widget-providers"; - private static final String TAG_PROVIDER = "provider"; - private static final String TAG_PACKAGE_LIST_ITEM = "item"; - private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; - private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; - private static final String TAG_DEFAULT_ENABLED_USER_RESTRICTIONS = - "default-enabled-user-restrictions"; - private static final String TAG_RESTRICTION = "restriction"; - private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; - private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; - private static final String TAG_PARENT_ADMIN = "parent-admin"; - private static final String TAG_ORGANIZATION_COLOR = "organization-color"; - private static final String TAG_ORGANIZATION_NAME = "organization-name"; - private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification"; - private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; - private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; - private static final String TAG_START_USER_SESSION_MESSAGE = "start_user_session_message"; - private static final String TAG_END_USER_SESSION_MESSAGE = "end_user_session_message"; - private static final String TAG_METERED_DATA_DISABLED_PACKAGES = - "metered_data_disabled_packages"; - private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES = - "cross-profile-calendar-packages"; - private static final String TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL = - "cross-profile-calendar-packages-null"; - private static final String TAG_CROSS_PROFILE_PACKAGES = "cross-profile-packages"; - private static final String TAG_FACTORY_RESET_PROTECTION_POLICY = - "factory_reset_protection_policy"; - private static final String TAG_SUSPEND_PERSONAL_APPS = "suspend-personal-apps"; - private static final String TAG_PROFILE_MAXIMUM_TIME_OFF = "profile-max-time-off"; - private static final String TAG_PROFILE_OFF_DEADLINE = "profile-off-deadline"; - private static final String TAG_ALWAYS_ON_VPN_PACKAGE = "vpn-package"; - private static final String TAG_ALWAYS_ON_VPN_LOCKDOWN = "vpn-lockdown"; - private static final String TAG_COMMON_CRITERIA_MODE = "common-criteria-mode"; - DeviceAdminInfo info; - - - static final int DEF_PASSWORD_HISTORY_LENGTH = 0; - int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH; - - @NonNull - PasswordPolicy mPasswordPolicy = new PasswordPolicy(); - - @Nullable - FactoryResetProtectionPolicy mFactoryResetProtectionPolicy = null; - - static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0; - long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK; - - long strongAuthUnlockTimeout = 0; // admin doesn't participate by default - - static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0; - int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE; - - static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0; - long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT; - - static final long DEF_PASSWORD_EXPIRATION_DATE = 0; - long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE; - - static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none - - int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED; - - boolean encryptionRequested = false; - boolean testOnlyAdmin = false; - boolean disableCamera = false; - boolean disableCallerId = false; - boolean disableContactsSearch = false; - boolean disableBluetoothContactSharing = true; - boolean disableScreenCapture = false; // Can only be set by a device/profile owner. - boolean requireAutoTime = false; // Can only be set by a device owner. - boolean forceEphemeralUsers = false; // Can only be set by a device owner. - boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner. - boolean isLogoutEnabled = false; // Can only be set by a device owner. - - // one notification after enabling + one more after reboots - static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2; - int numNetworkLoggingNotifications = 0; - long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch - - ActiveAdmin parentAdmin; - final boolean isParent; - - static class TrustAgentInfo { - public PersistableBundle options; - TrustAgentInfo(PersistableBundle bundle) { - options = bundle; - } - } - - // The list of packages which are not allowed to use metered data. - List<String> meteredDisabledPackages; - - final Set<String> accountTypesWithManagementDisabled = new ArraySet<>(); - - // The list of permitted accessibility services package namesas set by a profile - // or device owner. Null means all accessibility services are allowed, empty means - // none except system services are allowed. - List<String> permittedAccessiblityServices; - - // The list of permitted input methods package names as set by a profile or device owner. - // Null means all input methods are allowed, empty means none except system imes are - // allowed. - List<String> permittedInputMethods; - - // The list of packages allowed to use a NotificationListenerService to receive events for - // notifications from this user. Null means that all packages are allowed. Empty list means - // that only packages from the system are allowed. - List<String> permittedNotificationListeners; - - // List of package names to keep cached. - List<String> keepUninstalledPackages; - - // TODO: review implementation decisions with frameworks team - boolean specifiesGlobalProxy = false; - String globalProxySpec = null; - String globalProxyExclusionList = null; - - @NonNull ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>(); - - List<String> crossProfileWidgetProviders; - - Bundle userRestrictions; - - // User restrictions that have already been enabled by default for this admin (either when - // setting the device or profile owner, or during a system update if one of those "enabled - // by default" restrictions is newly added). - final Set<String> defaultEnabledRestrictionsAlreadySet = new ArraySet<>(); - - // Support text provided by the admin to display to the user. - CharSequence shortSupportMessage = null; - CharSequence longSupportMessage = null; - - // Background color of confirm credentials screen. Default: teal. - static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B"); - int organizationColor = DEF_ORGANIZATION_COLOR; - - // Default title of confirm credentials screen - String organizationName = null; - - // Message for user switcher - String startUserSessionMessage = null; - String endUserSessionMessage = null; - - // The whitelist of packages that can access cross profile calendar APIs. - // This whitelist should be in default an empty list, which indicates that no package - // is whitelisted. - List<String> mCrossProfileCalendarPackages = Collections.emptyList(); - - // The whitelist of packages that the admin has enabled to be able to request consent from - // the user to communicate cross-profile. By default, no packages are whitelisted, which is - // represented as an empty list. - List<String> mCrossProfilePackages = Collections.emptyList(); - - // Whether the admin explicitly requires personal apps to be suspended - boolean mSuspendPersonalApps = false; - // Maximum time the profile owned by this admin can be off. - long mProfileMaximumTimeOffMillis = 0; - // Time by which the profile should be turned on according to System.currentTimeMillis(). - long mProfileOffDeadline = 0; - - public String mAlwaysOnVpnPackage; - public boolean mAlwaysOnVpnLockdown; - boolean mCommonCriteriaMode; - - ActiveAdmin(DeviceAdminInfo _info, boolean parent) { - info = _info; - isParent = parent; - } - - ActiveAdmin getParentActiveAdmin() { - Preconditions.checkState(!isParent); - - if (parentAdmin == null) { - parentAdmin = new ActiveAdmin(info, /* parent */ true); - } - return parentAdmin; - } - - boolean hasParentActiveAdmin() { - return parentAdmin != null; - } - - int getUid() { return info.getActivityInfo().applicationInfo.uid; } - - public UserHandle getUserHandle() { - return UserHandle.of(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); - } - - void writeToXml(XmlSerializer out) - throws IllegalArgumentException, IllegalStateException, IOException { - out.startTag(null, TAG_POLICIES); - info.writePoliciesToXml(out); - out.endTag(null, TAG_POLICIES); - if (mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED) { - writeAttributeValueToXml( - out, TAG_PASSWORD_QUALITY, mPasswordPolicy.quality); - if (mPasswordPolicy.length != PasswordPolicy.DEF_MINIMUM_LENGTH) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LENGTH, mPasswordPolicy.length); - } - if (mPasswordPolicy.upperCase != PasswordPolicy.DEF_MINIMUM_UPPER_CASE) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_UPPERCASE, mPasswordPolicy.upperCase); - } - if (mPasswordPolicy.lowerCase != PasswordPolicy.DEF_MINIMUM_LOWER_CASE) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LOWERCASE, mPasswordPolicy.lowerCase); - } - if (mPasswordPolicy.letters != PasswordPolicy.DEF_MINIMUM_LETTERS) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_LETTERS, mPasswordPolicy.letters); - } - if (mPasswordPolicy.numeric != PasswordPolicy.DEF_MINIMUM_NUMERIC) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_NUMERIC, mPasswordPolicy.numeric); - } - if (mPasswordPolicy.symbols != PasswordPolicy.DEF_MINIMUM_SYMBOLS) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_SYMBOLS, mPasswordPolicy.symbols); - } - if (mPasswordPolicy.nonLetter > PasswordPolicy.DEF_MINIMUM_NON_LETTER) { - writeAttributeValueToXml( - out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter); - } - } - if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) { - writeAttributeValueToXml( - out, TAG_PASSWORD_HISTORY_LENGTH, passwordHistoryLength); - } - if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) { - writeAttributeValueToXml( - out, TAG_MAX_TIME_TO_UNLOCK, maximumTimeToUnlock); - } - if (strongAuthUnlockTimeout != DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) { - writeAttributeValueToXml( - out, TAG_STRONG_AUTH_UNLOCK_TIMEOUT, strongAuthUnlockTimeout); - } - if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) { - writeAttributeValueToXml( - out, TAG_MAX_FAILED_PASSWORD_WIPE, maximumFailedPasswordsForWipe); - } - if (specifiesGlobalProxy) { - writeAttributeValueToXml( - out, TAG_SPECIFIES_GLOBAL_PROXY, specifiesGlobalProxy); - if (globalProxySpec != null) { - writeAttributeValueToXml(out, TAG_GLOBAL_PROXY_SPEC, globalProxySpec); - } - if (globalProxyExclusionList != null) { - writeAttributeValueToXml( - out, TAG_GLOBAL_PROXY_EXCLUSION_LIST, globalProxyExclusionList); - } - } - if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) { - writeAttributeValueToXml( - out, TAG_PASSWORD_EXPIRATION_TIMEOUT, passwordExpirationTimeout); - } - if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) { - writeAttributeValueToXml( - out, TAG_PASSWORD_EXPIRATION_DATE, passwordExpirationDate); - } - if (encryptionRequested) { - writeAttributeValueToXml( - out, TAG_ENCRYPTION_REQUESTED, encryptionRequested); - } - if (testOnlyAdmin) { - writeAttributeValueToXml( - out, TAG_TEST_ONLY_ADMIN, testOnlyAdmin); - } - if (disableCamera) { - writeAttributeValueToXml( - out, TAG_DISABLE_CAMERA, disableCamera); - } - if (disableCallerId) { - writeAttributeValueToXml( - out, TAG_DISABLE_CALLER_ID, disableCallerId); - } - if (disableContactsSearch) { - writeAttributeValueToXml( - out, TAG_DISABLE_CONTACTS_SEARCH, disableContactsSearch); - } - if (!disableBluetoothContactSharing) { - writeAttributeValueToXml( - out, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING, disableBluetoothContactSharing); - } - if (disableScreenCapture) { - writeAttributeValueToXml( - out, TAG_DISABLE_SCREEN_CAPTURE, disableScreenCapture); - } - if (requireAutoTime) { - writeAttributeValueToXml( - out, TAG_REQUIRE_AUTO_TIME, requireAutoTime); - } - if (forceEphemeralUsers) { - writeAttributeValueToXml( - out, TAG_FORCE_EPHEMERAL_USERS, forceEphemeralUsers); - } - if (isNetworkLoggingEnabled) { - out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); - out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled)); - out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS, - Integer.toString(numNetworkLoggingNotifications)); - out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION, - Long.toString(lastNetworkLoggingNotificationTimeMs)); - out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED); - } - if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { - writeAttributeValueToXml( - out, TAG_DISABLE_KEYGUARD_FEATURES, disabledKeyguardFeatures); - } - if (!accountTypesWithManagementDisabled.isEmpty()) { - writeAttributeValuesToXml( - out, TAG_DISABLE_ACCOUNT_MANAGEMENT, TAG_ACCOUNT_TYPE, - accountTypesWithManagementDisabled); - } - if (!trustAgentInfos.isEmpty()) { - Set<Entry<String, TrustAgentInfo>> set = trustAgentInfos.entrySet(); - out.startTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); - for (Entry<String, TrustAgentInfo> entry : set) { - TrustAgentInfo trustAgentInfo = entry.getValue(); - out.startTag(null, TAG_TRUST_AGENT_COMPONENT); - out.attribute(null, ATTR_VALUE, entry.getKey()); - if (trustAgentInfo.options != null) { - out.startTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); - try { - trustAgentInfo.options.saveToXml(out); - } catch (XmlPullParserException e) { - Log.e(LOG_TAG, "Failed to save TrustAgent options", e); - } - out.endTag(null, TAG_TRUST_AGENT_COMPONENT_OPTIONS); - } - out.endTag(null, TAG_TRUST_AGENT_COMPONENT); - } - out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES); - } - if (crossProfileWidgetProviders != null && !crossProfileWidgetProviders.isEmpty()) { - writeAttributeValuesToXml( - out, TAG_CROSS_PROFILE_WIDGET_PROVIDERS, TAG_PROVIDER, - crossProfileWidgetProviders); - } - writePackageListToXml(out, TAG_PERMITTED_ACCESSIBILITY_SERVICES, - permittedAccessiblityServices); - writePackageListToXml(out, TAG_PERMITTED_IMES, permittedInputMethods); - writePackageListToXml(out, TAG_PERMITTED_NOTIFICATION_LISTENERS, - permittedNotificationListeners); - writePackageListToXml(out, TAG_KEEP_UNINSTALLED_PACKAGES, keepUninstalledPackages); - writePackageListToXml(out, TAG_METERED_DATA_DISABLED_PACKAGES, meteredDisabledPackages); - if (hasUserRestrictions()) { - UserRestrictionsUtils.writeRestrictions( - out, userRestrictions, TAG_USER_RESTRICTIONS); - } - if (!defaultEnabledRestrictionsAlreadySet.isEmpty()) { - writeAttributeValuesToXml(out, TAG_DEFAULT_ENABLED_USER_RESTRICTIONS, - TAG_RESTRICTION, - defaultEnabledRestrictionsAlreadySet); - } - if (!TextUtils.isEmpty(shortSupportMessage)) { - writeTextToXml(out, TAG_SHORT_SUPPORT_MESSAGE, shortSupportMessage.toString()); - } - if (!TextUtils.isEmpty(longSupportMessage)) { - writeTextToXml(out, TAG_LONG_SUPPORT_MESSAGE, longSupportMessage.toString()); - } - if (parentAdmin != null) { - out.startTag(null, TAG_PARENT_ADMIN); - parentAdmin.writeToXml(out); - out.endTag(null, TAG_PARENT_ADMIN); - } - if (organizationColor != DEF_ORGANIZATION_COLOR) { - writeAttributeValueToXml(out, TAG_ORGANIZATION_COLOR, organizationColor); - } - if (organizationName != null) { - writeTextToXml(out, TAG_ORGANIZATION_NAME, organizationName); - } - if (isLogoutEnabled) { - writeAttributeValueToXml(out, TAG_IS_LOGOUT_ENABLED, isLogoutEnabled); - } - if (startUserSessionMessage != null) { - writeTextToXml(out, TAG_START_USER_SESSION_MESSAGE, startUserSessionMessage); - } - if (endUserSessionMessage != null) { - writeTextToXml(out, TAG_END_USER_SESSION_MESSAGE, endUserSessionMessage); - } - if (mCrossProfileCalendarPackages == null) { - out.startTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); - out.endTag(null, TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL); - } else { - writePackageListToXml(out, TAG_CROSS_PROFILE_CALENDAR_PACKAGES, - mCrossProfileCalendarPackages); - } - writePackageListToXml(out, TAG_CROSS_PROFILE_PACKAGES, mCrossProfilePackages); - if (mFactoryResetProtectionPolicy != null) { - out.startTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); - mFactoryResetProtectionPolicy.writeToXml(out); - out.endTag(null, TAG_FACTORY_RESET_PROTECTION_POLICY); - } - if (mSuspendPersonalApps) { - writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps); - } - if (mProfileMaximumTimeOffMillis != 0) { - writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, - mProfileMaximumTimeOffMillis); - } - if (mProfileMaximumTimeOffMillis != 0) { - writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline); - } - if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) { - writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_PACKAGE, mAlwaysOnVpnPackage); - } - if (mAlwaysOnVpnLockdown) { - writeAttributeValueToXml(out, TAG_ALWAYS_ON_VPN_LOCKDOWN, mAlwaysOnVpnLockdown); - } - if (mCommonCriteriaMode) { - writeAttributeValueToXml(out, TAG_COMMON_CRITERIA_MODE, mCommonCriteriaMode); - } - } - - void writeTextToXml(XmlSerializer out, String tag, String text) throws IOException { - out.startTag(null, tag); - out.text(text); - out.endTag(null, tag); - } - - void writePackageListToXml(XmlSerializer out, String outerTag, - List<String> packageList) - throws IllegalArgumentException, IllegalStateException, IOException { - if (packageList == null) { - return; - } - writeAttributeValuesToXml(out, outerTag, TAG_PACKAGE_LIST_ITEM, packageList); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, String value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, value); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, int value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Integer.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, long value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Long.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValueToXml(XmlSerializer out, String tag, boolean value) - throws IOException { - out.startTag(null, tag); - out.attribute(null, ATTR_VALUE, Boolean.toString(value)); - out.endTag(null, tag); - } - - void writeAttributeValuesToXml(XmlSerializer out, String outerTag, String innerTag, - @NonNull Collection<String> values) throws IOException { - out.startTag(null, outerTag); - for (String value : values) { - out.startTag(null, innerTag); - out.attribute(null, ATTR_VALUE, value); - out.endTag(null, innerTag); - } - out.endTag(null, outerTag); - } - - void readFromXml(XmlPullParser parser, boolean shouldOverridePolicies) - throws XmlPullParserException, IOException { - int outerDepth = parser.getDepth(); - int type; - while ((type=parser.next()) != END_DOCUMENT - && (type != END_TAG || parser.getDepth() > outerDepth)) { - if (type == END_TAG || type == TEXT) { - continue; - } - String tag = parser.getName(); - if (TAG_POLICIES.equals(tag)) { - if (shouldOverridePolicies) { - Log.d(LOG_TAG, "Overriding device admin policies from XML."); - info.readPoliciesFromXml(parser); - } - } else if (TAG_PASSWORD_QUALITY.equals(tag)) { - mPasswordPolicy.quality = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LENGTH.equals(tag)) { - mPasswordPolicy.length = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PASSWORD_HISTORY_LENGTH.equals(tag)) { - passwordHistoryLength = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_UPPERCASE.equals(tag)) { - mPasswordPolicy.upperCase = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LOWERCASE.equals(tag)) { - mPasswordPolicy.lowerCase = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_LETTERS.equals(tag)) { - mPasswordPolicy.letters = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_NUMERIC.equals(tag)) { - mPasswordPolicy.numeric = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_SYMBOLS.equals(tag)) { - mPasswordPolicy.symbols = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) { - mPasswordPolicy.nonLetter = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - }else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) { - maximumTimeToUnlock = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) { - strongAuthUnlockTimeout = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_MAX_FAILED_PASSWORD_WIPE.equals(tag)) { - maximumFailedPasswordsForWipe = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_SPECIFIES_GLOBAL_PROXY.equals(tag)) { - specifiesGlobalProxy = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_GLOBAL_PROXY_SPEC.equals(tag)) { - globalProxySpec = - parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_GLOBAL_PROXY_EXCLUSION_LIST.equals(tag)) { - globalProxyExclusionList = - parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_PASSWORD_EXPIRATION_TIMEOUT.equals(tag)) { - passwordExpirationTimeout = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PASSWORD_EXPIRATION_DATE.equals(tag)) { - passwordExpirationDate = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ENCRYPTION_REQUESTED.equals(tag)) { - encryptionRequested = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_TEST_ONLY_ADMIN.equals(tag)) { - testOnlyAdmin = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CAMERA.equals(tag)) { - disableCamera = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CALLER_ID.equals(tag)) { - disableCallerId = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_CONTACTS_SEARCH.equals(tag)) { - disableContactsSearch = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) { - disableBluetoothContactSharing = Boolean.parseBoolean(parser - .getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) { - disableScreenCapture = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_REQUIRE_AUTO_TIME.equals(tag)) { - requireAutoTime = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_FORCE_EPHEMERAL_USERS.equals(tag)) { - forceEphemeralUsers = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) { - isNetworkLoggingEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - lastNetworkLoggingNotificationTimeMs = Long.parseLong( - parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION)); - numNetworkLoggingNotifications = Integer.parseInt( - parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS)); - } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { - disabledKeyguardFeatures = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) { - readAttributeValues( - parser, TAG_ACCOUNT_TYPE, accountTypesWithManagementDisabled); - } else if (TAG_MANAGE_TRUST_AGENT_FEATURES.equals(tag)) { - trustAgentInfos = getAllTrustAgentInfos(parser, tag); - } else if (TAG_CROSS_PROFILE_WIDGET_PROVIDERS.equals(tag)) { - crossProfileWidgetProviders = new ArrayList<>(); - readAttributeValues(parser, TAG_PROVIDER, crossProfileWidgetProviders); - } else if (TAG_PERMITTED_ACCESSIBILITY_SERVICES.equals(tag)) { - permittedAccessiblityServices = readPackageList(parser, tag); - } else if (TAG_PERMITTED_IMES.equals(tag)) { - permittedInputMethods = readPackageList(parser, tag); - } else if (TAG_PERMITTED_NOTIFICATION_LISTENERS.equals(tag)) { - permittedNotificationListeners = readPackageList(parser, tag); - } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) { - keepUninstalledPackages = readPackageList(parser, tag); - } else if (TAG_METERED_DATA_DISABLED_PACKAGES.equals(tag)) { - meteredDisabledPackages = readPackageList(parser, tag); - } else if (TAG_USER_RESTRICTIONS.equals(tag)) { - userRestrictions = UserRestrictionsUtils.readRestrictions(parser); - } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) { - readAttributeValues( - parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet); - } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - shortSupportMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading short support message"); - } - } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - longSupportMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading long support message"); - } - } else if (TAG_PARENT_ADMIN.equals(tag)) { - Preconditions.checkState(!isParent); - parentAdmin = new ActiveAdmin(info, /* parent */ true); - parentAdmin.readFromXml(parser, shouldOverridePolicies); - } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { - organizationColor = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ORGANIZATION_NAME.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - organizationName = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading organization name"); - } - } else if (TAG_IS_LOGOUT_ENABLED.equals(tag)) { - isLogoutEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_START_USER_SESSION_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - startUserSessionMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading start session message"); - } - } else if (TAG_END_USER_SESSION_MESSAGE.equals(tag)) { - type = parser.next(); - if (type == XmlPullParser.TEXT) { - endUserSessionMessage = parser.getText(); - } else { - Log.w(LOG_TAG, "Missing text when loading end session message"); - } - } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES.equals(tag)) { - mCrossProfileCalendarPackages = readPackageList(parser, tag); - } else if (TAG_CROSS_PROFILE_CALENDAR_PACKAGES_NULL.equals(tag)) { - mCrossProfileCalendarPackages = null; - } else if (TAG_CROSS_PROFILE_PACKAGES.equals(tag)) { - mCrossProfilePackages = readPackageList(parser, tag); - } else if (TAG_FACTORY_RESET_PROTECTION_POLICY.equals(tag)) { - mFactoryResetProtectionPolicy = FactoryResetProtectionPolicy.readFromXml( - parser); - } else if (TAG_SUSPEND_PERSONAL_APPS.equals(tag)) { - mSuspendPersonalApps = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) { - mProfileMaximumTimeOffMillis = - Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) { - mProfileOffDeadline = - Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ALWAYS_ON_VPN_PACKAGE.equals(tag)) { - mAlwaysOnVpnPackage = parser.getAttributeValue(null, ATTR_VALUE); - } else if (TAG_ALWAYS_ON_VPN_LOCKDOWN.equals(tag)) { - mAlwaysOnVpnLockdown = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_COMMON_CRITERIA_MODE.equals(tag)) { - mCommonCriteriaMode = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.w(LOG_TAG, "Unknown admin tag: " + tag); - XmlUtils.skipCurrentTag(parser); - } - } - } - - private List<String> readPackageList(XmlPullParser parser, - String tag) throws XmlPullParserException, IOException { - List<String> result = new ArrayList<String>(); - int outerDepth = parser.getDepth(); - int outerType; - while ((outerType=parser.next()) != XmlPullParser.END_DOCUMENT - && (outerType != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (outerType == XmlPullParser.END_TAG || outerType == XmlPullParser.TEXT) { - continue; - } - String outerTag = parser.getName(); - if (TAG_PACKAGE_LIST_ITEM.equals(outerTag)) { - String packageName = parser.getAttributeValue(null, ATTR_VALUE); - if (packageName != null) { - result.add(packageName); - } else { - Slog.w(LOG_TAG, "Package name missing under " + outerTag); - } - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + outerTag); - } - } - return result; - } - - private void readAttributeValues( - XmlPullParser parser, String tag, Collection<String> result) - throws XmlPullParserException, IOException { - result.clear(); - int outerDepthDAM = parser.getDepth(); - int typeDAM; - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (tag.equals(tagDAM)) { - result.add(parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.e(LOG_TAG, "Expected tag " + tag + " but found " + tagDAM); - } - } - } - - @NonNull - private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos( - XmlPullParser parser, String tag) throws XmlPullParserException, IOException { - int outerDepthDAM = parser.getDepth(); - int typeDAM; - final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>(); - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (TAG_TRUST_AGENT_COMPONENT.equals(tagDAM)) { - final String component = parser.getAttributeValue(null, ATTR_VALUE); - final TrustAgentInfo trustAgentInfo = getTrustAgentInfo(parser, tag); - result.put(component, trustAgentInfo); - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM); - } - } - return result; - } - - private TrustAgentInfo getTrustAgentInfo(XmlPullParser parser, String tag) - throws XmlPullParserException, IOException { - int outerDepthDAM = parser.getDepth(); - int typeDAM; - TrustAgentInfo result = new TrustAgentInfo(null); - while ((typeDAM=parser.next()) != END_DOCUMENT - && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { - if (typeDAM == END_TAG || typeDAM == TEXT) { - continue; - } - String tagDAM = parser.getName(); - if (TAG_TRUST_AGENT_COMPONENT_OPTIONS.equals(tagDAM)) { - result.options = PersistableBundle.restoreFromXml(parser); - } else { - Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM); - } - } - return result; - } - - boolean hasUserRestrictions() { - return userRestrictions != null && userRestrictions.size() > 0; - } - - Bundle ensureUserRestrictions() { - if (userRestrictions == null) { - userRestrictions = new Bundle(); - } - return userRestrictions; - } - - public void transfer(DeviceAdminInfo deviceAdminInfo) { - if (hasParentActiveAdmin()) { - parentAdmin.info = deviceAdminInfo; - } - info = deviceAdminInfo; - } - - Bundle addSyntheticRestrictions(Bundle restrictions) { - if (disableCamera) { - restrictions.putBoolean(UserManager.DISALLOW_CAMERA, true); - } - if (requireAutoTime) { - restrictions.putBoolean(UserManager.DISALLOW_CONFIG_DATE_TIME, true); - } - return restrictions; - } - - static Bundle removeDeprecatedRestrictions(Bundle restrictions) { - for (String deprecatedRestriction: DEPRECATED_USER_RESTRICTIONS) { - restrictions.remove(deprecatedRestriction); - } - return restrictions; - } - - static Bundle filterRestrictions(Bundle restrictions, Predicate<String> filter) { - Bundle result = new Bundle(); - for (String key : restrictions.keySet()) { - if (!restrictions.getBoolean(key)) { - continue; - } - if (filter.test(key)) { - result.putBoolean(key, true); - } - } - return result; - } - - Bundle getEffectiveRestrictions() { - return addSyntheticRestrictions( - removeDeprecatedRestrictions(new Bundle(ensureUserRestrictions()))); - } - - Bundle getLocalUserRestrictions(int adminType) { - return filterRestrictions(getEffectiveRestrictions(), - key -> UserRestrictionsUtils.isLocal(adminType, key)); - } - - Bundle getGlobalUserRestrictions(int adminType) { - return filterRestrictions(getEffectiveRestrictions(), - key -> UserRestrictionsUtils.isGlobal(adminType, key)); - } - - void dump(IndentingPrintWriter pw) { - pw.print("uid="); pw.println(getUid()); - pw.print("testOnlyAdmin="); - pw.println(testOnlyAdmin); - pw.println("policies:"); - ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies(); - if (pols != null) { - pw.increaseIndent(); - for (int i=0; i<pols.size(); i++) { - pw.println(pols.get(i).tag); - } - pw.decreaseIndent(); - } - pw.print("passwordQuality=0x"); - pw.println(Integer.toHexString(mPasswordPolicy.quality)); - pw.print("minimumPasswordLength="); - pw.println(mPasswordPolicy.length); - pw.print("passwordHistoryLength="); - pw.println(passwordHistoryLength); - pw.print("minimumPasswordUpperCase="); - pw.println(mPasswordPolicy.upperCase); - pw.print("minimumPasswordLowerCase="); - pw.println(mPasswordPolicy.lowerCase); - pw.print("minimumPasswordLetters="); - pw.println(mPasswordPolicy.letters); - pw.print("minimumPasswordNumeric="); - pw.println(mPasswordPolicy.numeric); - pw.print("minimumPasswordSymbols="); - pw.println(mPasswordPolicy.symbols); - pw.print("minimumPasswordNonLetter="); - pw.println(mPasswordPolicy.nonLetter); - pw.print("maximumTimeToUnlock="); - pw.println(maximumTimeToUnlock); - pw.print("strongAuthUnlockTimeout="); - pw.println(strongAuthUnlockTimeout); - pw.print("maximumFailedPasswordsForWipe="); - pw.println(maximumFailedPasswordsForWipe); - pw.print("specifiesGlobalProxy="); - pw.println(specifiesGlobalProxy); - pw.print("passwordExpirationTimeout="); - pw.println(passwordExpirationTimeout); - pw.print("passwordExpirationDate="); - pw.println(passwordExpirationDate); - if (globalProxySpec != null) { - pw.print("globalProxySpec="); - pw.println(globalProxySpec); - } - if (globalProxyExclusionList != null) { - pw.print("globalProxyEclusionList="); - pw.println(globalProxyExclusionList); - } - pw.print("encryptionRequested="); - pw.println(encryptionRequested); - pw.print("disableCamera="); - pw.println(disableCamera); - pw.print("disableCallerId="); - pw.println(disableCallerId); - pw.print("disableContactsSearch="); - pw.println(disableContactsSearch); - pw.print("disableBluetoothContactSharing="); - pw.println(disableBluetoothContactSharing); - pw.print("disableScreenCapture="); - pw.println(disableScreenCapture); - pw.print("requireAutoTime="); - pw.println(requireAutoTime); - pw.print("forceEphemeralUsers="); - pw.println(forceEphemeralUsers); - pw.print("isNetworkLoggingEnabled="); - pw.println(isNetworkLoggingEnabled); - pw.print("disabledKeyguardFeatures="); - pw.println(disabledKeyguardFeatures); - pw.print("crossProfileWidgetProviders="); - pw.println(crossProfileWidgetProviders); - if (permittedAccessiblityServices != null) { - pw.print("permittedAccessibilityServices="); - pw.println(permittedAccessiblityServices); - } - if (permittedInputMethods != null) { - pw.print("permittedInputMethods="); - pw.println(permittedInputMethods); - } - if (permittedNotificationListeners != null) { - pw.print("permittedNotificationListeners="); - pw.println(permittedNotificationListeners); - } - if (keepUninstalledPackages != null) { - pw.print("keepUninstalledPackages="); - pw.println(keepUninstalledPackages); - } - pw.print("organizationColor="); - pw.println(organizationColor); - if (organizationName != null) { - pw.print("organizationName="); - pw.println(organizationName); - } - pw.println("userRestrictions:"); - UserRestrictionsUtils.dumpRestrictions(pw, " ", userRestrictions); - pw.print("defaultEnabledRestrictionsAlreadySet="); - pw.println(defaultEnabledRestrictionsAlreadySet); - pw.print("isParent="); - pw.println(isParent); - if (parentAdmin != null) { - pw.println("parentAdmin:"); - pw.increaseIndent(); - parentAdmin.dump(pw); - pw.decreaseIndent(); - } - if (mCrossProfileCalendarPackages != null) { - pw.print("mCrossProfileCalendarPackages="); - pw.println(mCrossProfileCalendarPackages); - } - pw.print("mCrossProfilePackages="); - pw.println(mCrossProfilePackages); - pw.print("mSuspendPersonalApps="); - pw.println(mSuspendPersonalApps); - pw.print("mProfileMaximumTimeOffMillis="); - pw.println(mProfileMaximumTimeOffMillis); - pw.print("mProfileOffDeadline="); - pw.println(mProfileOffDeadline); - pw.print("mAlwaysOnVpnPackage="); - pw.println(mAlwaysOnVpnPackage); - pw.print("mAlwaysOnVpnLockdown="); - pw.println(mAlwaysOnVpnLockdown); - pw.print("mCommonCriteriaMode="); - pw.println(mCommonCriteriaMode); - } - } - private void handlePackagesChanged(@Nullable String packageName, int userHandle) { boolean removedAdmin = false; if (VERBOSE_LOG) { @@ -2073,7 +934,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } if (removedAdmin) { - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); } boolean removedDelegate = false; @@ -3514,13 +2375,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - - public DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle, + private DeviceAdminInfo findAdmin(final ComponentName adminName, final int userHandle, boolean throwForMissingPermission) { - if (!mHasFeature) { - return null; - } - enforceFullCrossUsersPermission(userHandle); final ActivityInfo ai = mInjector.binderWithCleanCallingIdentity(() -> { try { return mIPackageManager.getReceiverInfo(adminName, @@ -3583,213 +2439,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void saveSettingsLocked(int userHandle) { - DevicePolicyData policy = getUserData(userHandle); - JournaledFile journal = makeJournaledFile(userHandle); - FileOutputStream stream = null; - try { - stream = new FileOutputStream(journal.chooseForWrite(), false); - XmlSerializer out = new FastXmlSerializer(); - out.setOutput(stream, StandardCharsets.UTF_8.name()); - out.startDocument(null, true); - - out.startTag(null, "policies"); - if (policy.mRestrictionsProvider != null) { - out.attribute(null, ATTR_PERMISSION_PROVIDER, - policy.mRestrictionsProvider.flattenToString()); - } - if (policy.mUserSetupComplete) { - out.attribute(null, ATTR_SETUP_COMPLETE, - Boolean.toString(true)); - } - if (policy.mPaired) { - out.attribute(null, ATTR_DEVICE_PAIRED, - Boolean.toString(true)); - } - if (policy.mDeviceProvisioningConfigApplied) { - out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED, - Boolean.toString(true)); - } - if (policy.mUserProvisioningState != DevicePolicyManager.STATE_USER_UNMANAGED) { - out.attribute(null, ATTR_PROVISIONING_STATE, - Integer.toString(policy.mUserProvisioningState)); - } - if (policy.mPermissionPolicy != DevicePolicyManager.PERMISSION_POLICY_PROMPT) { - out.attribute(null, ATTR_PERMISSION_POLICY, - Integer.toString(policy.mPermissionPolicy)); - } - - // Serialize delegations. - for (int i = 0; i < policy.mDelegationMap.size(); ++i) { - final String delegatePackage = policy.mDelegationMap.keyAt(i); - final List<String> scopes = policy.mDelegationMap.valueAt(i); - - // Every "delegation" tag serializes the information of one delegate-scope pair. - for (String scope : scopes) { - out.startTag(null, "delegation"); - out.attribute(null, "delegatePackage", delegatePackage); - out.attribute(null, "scope", scope); - out.endTag(null, "delegation"); - } - } - - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin ap = policy.mAdminList.get(i); - if (ap != null) { - out.startTag(null, "admin"); - out.attribute(null, "name", ap.info.getComponent().flattenToString()); - ap.writeToXml(out); - out.endTag(null, "admin"); - } - } - - if (policy.mPasswordOwner >= 0) { - out.startTag(null, "password-owner"); - out.attribute(null, "value", Integer.toString(policy.mPasswordOwner)); - out.endTag(null, "password-owner"); - } - - if (policy.mFailedPasswordAttempts != 0) { - out.startTag(null, "failed-password-attempts"); - out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts)); - out.endTag(null, "failed-password-attempts"); - } - - // For FDE devices only, we save this flag so we can report on password sufficiency - // before the user enters their password for the first time after a reboot. For - // security reasons, we don't want to store the full set of active password metrics. - if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) { - out.startTag(null, TAG_PASSWORD_VALIDITY); - out.attribute(null, ATTR_VALUE, - Boolean.toString(policy.mPasswordValidAtLastCheckpoint)); - out.endTag(null, TAG_PASSWORD_VALIDITY); - } - - for (int i = 0; i < policy.mAcceptedCaCertificates.size(); i++) { - out.startTag(null, TAG_ACCEPTED_CA_CERTIFICATES); - out.attribute(null, ATTR_NAME, policy.mAcceptedCaCertificates.valueAt(i)); - out.endTag(null, TAG_ACCEPTED_CA_CERTIFICATES); - } - - for (int i=0; i<policy.mLockTaskPackages.size(); i++) { - String component = policy.mLockTaskPackages.get(i); - out.startTag(null, TAG_LOCK_TASK_COMPONENTS); - out.attribute(null, "name", component); - out.endTag(null, TAG_LOCK_TASK_COMPONENTS); - } - - if (policy.mLockTaskFeatures != DevicePolicyManager.LOCK_TASK_FEATURE_NONE) { - out.startTag(null, TAG_LOCK_TASK_FEATURES); - out.attribute(null, ATTR_VALUE, Integer.toString(policy.mLockTaskFeatures)); - out.endTag(null, TAG_LOCK_TASK_FEATURES); - } - - if (policy.mSecondaryLockscreenEnabled) { - out.startTag(null, TAG_SECONDARY_LOCK_SCREEN); - out.attribute(null, ATTR_VALUE, Boolean.toString(true)); - out.endTag(null, TAG_SECONDARY_LOCK_SCREEN); - } - - if (policy.mStatusBarDisabled) { - out.startTag(null, TAG_STATUS_BAR); - out.attribute(null, ATTR_DISABLED, Boolean.toString(policy.mStatusBarDisabled)); - out.endTag(null, TAG_STATUS_BAR); - } - - if (policy.doNotAskCredentialsOnBoot) { - out.startTag(null, DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML); - out.endTag(null, DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML); - } - - for (String id : policy.mAffiliationIds) { - out.startTag(null, TAG_AFFILIATION_ID); - out.attribute(null, ATTR_ID, id); - out.endTag(null, TAG_AFFILIATION_ID); - } - - if (policy.mLastSecurityLogRetrievalTime >= 0) { - out.startTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastSecurityLogRetrievalTime)); - out.endTag(null, TAG_LAST_SECURITY_LOG_RETRIEVAL); - } - - if (policy.mLastBugReportRequestTime >= 0) { - out.startTag(null, TAG_LAST_BUG_REPORT_REQUEST); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastBugReportRequestTime)); - out.endTag(null, TAG_LAST_BUG_REPORT_REQUEST); - } - - if (policy.mLastNetworkLogsRetrievalTime >= 0) { - out.startTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mLastNetworkLogsRetrievalTime)); - out.endTag(null, TAG_LAST_NETWORK_LOG_RETRIEVAL); - } - - if (policy.mAdminBroadcastPending) { - out.startTag(null, TAG_ADMIN_BROADCAST_PENDING); - out.attribute(null, ATTR_VALUE, - Boolean.toString(policy.mAdminBroadcastPending)); - out.endTag(null, TAG_ADMIN_BROADCAST_PENDING); - } - - if (policy.mInitBundle != null) { - out.startTag(null, TAG_INITIALIZATION_BUNDLE); - policy.mInitBundle.saveToXml(out); - out.endTag(null, TAG_INITIALIZATION_BUNDLE); - } - - if (policy.mPasswordTokenHandle != 0) { - out.startTag(null, TAG_PASSWORD_TOKEN_HANDLE); - out.attribute(null, ATTR_VALUE, - Long.toString(policy.mPasswordTokenHandle)); - out.endTag(null, TAG_PASSWORD_TOKEN_HANDLE); - } - - if (policy.mCurrentInputMethodSet) { - out.startTag(null, TAG_CURRENT_INPUT_METHOD_SET); - out.endTag(null, TAG_CURRENT_INPUT_METHOD_SET); - } - - for (final String cert : policy.mOwnerInstalledCaCerts) { - out.startTag(null, TAG_OWNER_INSTALLED_CA_CERT); - out.attribute(null, ATTR_ALIAS, cert); - out.endTag(null, TAG_OWNER_INSTALLED_CA_CERT); - } - - for (int i = 0, size = policy.mUserControlDisabledPackages.size(); i < size; i++) { - String packageName = policy.mUserControlDisabledPackages.get(i); - out.startTag(null, TAG_PROTECTED_PACKAGES); - out.attribute(null, ATTR_NAME, packageName); - out.endTag(null, TAG_PROTECTED_PACKAGES); - } - - if (policy.mAppsSuspended) { - out.startTag(null, TAG_APPS_SUSPENDED); - out.attribute(null, ATTR_VALUE, Boolean.toString(policy.mAppsSuspended)); - out.endTag(null, TAG_APPS_SUSPENDED); - } - - out.endTag(null, "policies"); - - out.endDocument(); - stream.flush(); - FileUtils.sync(stream); - stream.close(); - journal.commit(); + if (DevicePolicyData.store( + getUserData(userHandle), + makeJournaledFile(userHandle), + !mInjector.storageManagerIsFileBasedEncryptionEnabled())) { sendChangedNotification(userHandle); - } catch (XmlPullParserException | IOException e) { - Slog.w(LOG_TAG, "failed writing file", e); - try { - if (stream != null) { - stream.close(); - } - } catch (IOException ex) { - // Ignore - } - journal.rollback(); } } @@ -3801,225 +2455,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { - JournaledFile journal = makeJournaledFile(userHandle); - FileInputStream stream = null; - File file = journal.chooseForRead(); - boolean needsRewrite = false; - try { - stream = new FileInputStream(file); - XmlPullParser parser = Xml.newPullParser(); - parser.setInput(stream, StandardCharsets.UTF_8.name()); - - int type; - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && type != XmlPullParser.START_TAG) { - } - String tag = parser.getName(); - if (!"policies".equals(tag)) { - throw new XmlPullParserException( - "Settings do not start with policies tag: found " + tag); - } - - // Extract the permission provider component name if available - String permissionProvider = parser.getAttributeValue(null, ATTR_PERMISSION_PROVIDER); - if (permissionProvider != null) { - policy.mRestrictionsProvider = ComponentName.unflattenFromString(permissionProvider); - } - String userSetupComplete = parser.getAttributeValue(null, ATTR_SETUP_COMPLETE); - if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) { - policy.mUserSetupComplete = true; - } - String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED); - if (paired != null && Boolean.toString(true).equals(paired)) { - policy.mPaired = true; - } - String deviceProvisioningConfigApplied = parser.getAttributeValue(null, - ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED); - if (deviceProvisioningConfigApplied != null - && Boolean.toString(true).equals(deviceProvisioningConfigApplied)) { - policy.mDeviceProvisioningConfigApplied = true; - } - String provisioningState = parser.getAttributeValue(null, ATTR_PROVISIONING_STATE); - if (!TextUtils.isEmpty(provisioningState)) { - policy.mUserProvisioningState = Integer.parseInt(provisioningState); - } - String permissionPolicy = parser.getAttributeValue(null, ATTR_PERMISSION_POLICY); - if (!TextUtils.isEmpty(permissionPolicy)) { - policy.mPermissionPolicy = Integer.parseInt(permissionPolicy); - } - // Check for delegation compatibility with pre-O. - // TODO(edmanp) remove in P. - { - final String certDelegate = parser.getAttributeValue(null, - ATTR_DELEGATED_CERT_INSTALLER); - if (certDelegate != null) { - List<String> scopes = policy.mDelegationMap.get(certDelegate); - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(certDelegate, scopes); - } - if (!scopes.contains(DELEGATION_CERT_INSTALL)) { - scopes.add(DELEGATION_CERT_INSTALL); - needsRewrite = true; - } - } - final String appRestrictionsDelegate = parser.getAttributeValue(null, - ATTR_APPLICATION_RESTRICTIONS_MANAGER); - if (appRestrictionsDelegate != null) { - List<String> scopes = policy.mDelegationMap.get(appRestrictionsDelegate); - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(appRestrictionsDelegate, scopes); - } - if (!scopes.contains(DELEGATION_APP_RESTRICTIONS)) { - scopes.add(DELEGATION_APP_RESTRICTIONS); - needsRewrite = true; - } - } - } - - type = parser.next(); - int outerDepth = parser.getDepth(); - policy.mLockTaskPackages.clear(); - policy.mAdminList.clear(); - policy.mAdminMap.clear(); - policy.mAffiliationIds.clear(); - policy.mOwnerInstalledCaCerts.clear(); - policy.mUserControlDisabledPackages.clear(); - while ((type=parser.next()) != XmlPullParser.END_DOCUMENT - && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { - if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { - continue; - } - tag = parser.getName(); - if ("admin".equals(tag)) { - String name = parser.getAttributeValue(null, "name"); - try { - DeviceAdminInfo dai = findAdmin( - ComponentName.unflattenFromString(name), userHandle, - /* throwForMissingPermission= */ false); - if (VERBOSE_LOG - && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) - != userHandle)) { - Slog.w(LOG_TAG, "findAdmin returned an incorrect uid " - + dai.getActivityInfo().applicationInfo.uid + " for user " - + userHandle); - } - if (dai != null) { - boolean shouldOverwritePolicies = - shouldOverwritePoliciesFromXml(dai.getComponent(), userHandle); - ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); - ap.readFromXml(parser, shouldOverwritePolicies); - policy.mAdminMap.put(ap.info.getComponent(), ap); - } - } catch (RuntimeException e) { - Slog.w(LOG_TAG, "Failed loading admin " + name, e); - } - } else if ("delegation".equals(tag)) { - // Parse delegation info. - final String delegatePackage = parser.getAttributeValue(null, - "delegatePackage"); - final String scope = parser.getAttributeValue(null, "scope"); - - // Get a reference to the scopes list for the delegatePackage. - List<String> scopes = policy.mDelegationMap.get(delegatePackage); - // Or make a new list if none was found. - if (scopes == null) { - scopes = new ArrayList<>(); - policy.mDelegationMap.put(delegatePackage, scopes); - } - // Add the new scope to the list of delegatePackage if it's not already there. - if (!scopes.contains(scope)) { - scopes.add(scope); - } - } else if ("failed-password-attempts".equals(tag)) { - policy.mFailedPasswordAttempts = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if ("password-owner".equals(tag)) { - policy.mPasswordOwner = Integer.parseInt( - parser.getAttributeValue(null, "value")); - } else if (TAG_ACCEPTED_CA_CERTIFICATES.equals(tag)) { - policy.mAcceptedCaCertificates.add(parser.getAttributeValue(null, ATTR_NAME)); - } else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) { - policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name")); - } else if (TAG_LOCK_TASK_FEATURES.equals(tag)) { - policy.mLockTaskFeatures = Integer.parseInt( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_SECONDARY_LOCK_SCREEN.equals(tag)) { - policy.mSecondaryLockscreenEnabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_STATUS_BAR.equals(tag)) { - policy.mStatusBarDisabled = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_DISABLED)); - } else if (DO_NOT_ASK_CREDENTIALS_ON_BOOT_XML.equals(tag)) { - policy.doNotAskCredentialsOnBoot = true; - } else if (TAG_AFFILIATION_ID.equals(tag)) { - policy.mAffiliationIds.add(parser.getAttributeValue(null, ATTR_ID)); - } else if (TAG_LAST_SECURITY_LOG_RETRIEVAL.equals(tag)) { - policy.mLastSecurityLogRetrievalTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_LAST_BUG_REPORT_REQUEST.equals(tag)) { - policy.mLastBugReportRequestTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_LAST_NETWORK_LOG_RETRIEVAL.equals(tag)) { - policy.mLastNetworkLogsRetrievalTime = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_ADMIN_BROADCAST_PENDING.equals(tag)) { - String pending = parser.getAttributeValue(null, ATTR_VALUE); - policy.mAdminBroadcastPending = Boolean.toString(true).equals(pending); - } else if (TAG_INITIALIZATION_BUNDLE.equals(tag)) { - policy.mInitBundle = PersistableBundle.restoreFromXml(parser); - } else if ("active-password".equals(tag)) { - // Remove password metrics from saved settings, as we no longer wish to store - // these on disk - needsRewrite = true; - } else if (TAG_PASSWORD_VALIDITY.equals(tag)) { - if (!mInjector.storageManagerIsFileBasedEncryptionEnabled()) { - // This flag is only used for FDE devices - policy.mPasswordValidAtLastCheckpoint = Boolean.parseBoolean( - parser.getAttributeValue(null, ATTR_VALUE)); - } - } else if (TAG_PASSWORD_TOKEN_HANDLE.equals(tag)) { - policy.mPasswordTokenHandle = Long.parseLong( - parser.getAttributeValue(null, ATTR_VALUE)); - } else if (TAG_CURRENT_INPUT_METHOD_SET.equals(tag)) { - policy.mCurrentInputMethodSet = true; - } else if (TAG_OWNER_INSTALLED_CA_CERT.equals(tag)) { - policy.mOwnerInstalledCaCerts.add(parser.getAttributeValue(null, ATTR_ALIAS)); - } else if (TAG_PROTECTED_PACKAGES.equals(tag)) { - policy.mUserControlDisabledPackages.add( - parser.getAttributeValue(null, ATTR_NAME)); - } else if (TAG_APPS_SUSPENDED.equals(tag)) { - policy.mAppsSuspended = - Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_VALUE)); - } else { - Slog.w(LOG_TAG, "Unknown tag: " + tag); - XmlUtils.skipCurrentTag(parser); - } - } - } catch (FileNotFoundException e) { - // Don't be noisy, this is normal if we haven't defined any policies. - } catch (NullPointerException | NumberFormatException | XmlPullParserException | IOException - | IndexOutOfBoundsException e) { - Slog.w(LOG_TAG, "failed parsing " + file, e); - } - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - // Ignore - } - - // Generate a list of admins from the admin map - policy.mAdminList.addAll(policy.mAdminMap.values()); + boolean needsRewrite = DevicePolicyData.load(policy, + !mInjector.storageManagerIsFileBasedEncryptionEnabled(), + makeJournaledFile(userHandle), + component -> findAdmin( + component, userHandle, /* throwForMissingPermission= */ false), + getOwnerComponent(userHandle)); // Might need to upgrade the file by rewriting it if (needsRewrite) { saveSettingsLocked(userHandle); } - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); updateMaximumTimeToLockLocked(userHandle); updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle); updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle); @@ -4029,14 +2477,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - private boolean shouldOverwritePoliciesFromXml( - ComponentName deviceAdminComponent, int userHandle) { - // http://b/123415062: If DA, overwrite with the stored policies that were agreed by the - // user to prevent apps from sneaking additional policies into updates. - return !isProfileOwner(deviceAdminComponent, userHandle) - && !isDeviceOwner(deviceAdminComponent, userHandle); - } - private void updateLockTaskPackagesLocked(List<String> packages, int userId) { long ident = mInjector.binderClearCallingIdentity(); try { @@ -4098,23 +2538,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + Integer.toHexString(quality)); } - void validatePasswordOwnerLocked(DevicePolicyData policy) { - if (policy.mPasswordOwner >= 0) { - boolean haveOwner = false; - for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { - if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) { - haveOwner = true; - break; - } - } - if (!haveOwner) { - Slog.w(LOG_TAG, "Previous password owner " + policy.mPasswordOwner - + " no longer active; disabling"); - policy.mPasswordOwner = -1; - } - } - } - @VisibleForTesting @Override void systemReady(int phase) { @@ -5842,8 +4265,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private void setDoNotAskCredentialsOnBoot() { synchronized (getLockObject()) { DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); - if (!policyData.doNotAskCredentialsOnBoot) { - policyData.doNotAskCredentialsOnBoot = true; + if (!policyData.mDoNotAskCredentialsOnBoot) { + policyData.mDoNotAskCredentialsOnBoot = true; saveSettingsLocked(UserHandle.USER_SYSTEM); } } @@ -5855,7 +4278,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null); synchronized (getLockObject()) { DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); - return policyData.doNotAskCredentialsOnBoot; + return policyData.mDoNotAskCredentialsOnBoot; } } @@ -14363,7 +12786,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); policy.mAdminList.remove(admin); policy.mAdminMap.remove(adminReceiver); - validatePasswordOwnerLocked(policy); + policy.validatePasswordOwner(); if (doProxyCleanup) { resetGlobalProxyLocked(policy); } diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index a5f0d045948c..f7082a9a1a0c 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -23,7 +23,6 @@ #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <binder/AppOpsManager.h> -#include <binder/Nullable.h> #include <binder/Status.h> #include <sys/stat.h> #include <uuid/uuid.h> @@ -1404,7 +1403,7 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara } FileSystemControlParcel fsControlParcel; - fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>(); + fsControlParcel.incremental = std::make_optional<IncrementalFileSystemControlParcel>(); fsControlParcel.incremental->cmd.reset(dup(ifs.control.cmd())); fsControlParcel.incremental->pendingReads.reset(dup(ifs.control.pendingReads())); fsControlParcel.incremental->log.reset(dup(ifs.control.logs())); diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp index cffcdd8f94bd..e4e7e2288590 100644 --- a/services/tests/PackageManagerServiceTests/host/Android.bp +++ b/services/tests/PackageManagerServiceTests/host/Android.bp @@ -32,6 +32,7 @@ java_test_host { ":PackageManagerTestAppVersion3Invalid", ":PackageManagerTestAppVersion4", ":PackageManagerTestAppOriginalOverride", + ":PackageManagerServiceDeviceSideTests", ], } diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt new file mode 100644 index 000000000000..3847658def6a --- /dev/null +++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/FactoryPackageTest.kt @@ -0,0 +1,71 @@ +package com.android.server.pm.test + +import com.android.internal.util.test.SystemPreparer +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test +import org.junit.rules.RuleChain +import org.junit.rules.TemporaryFolder +import org.junit.runner.RunWith + +@RunWith(DeviceJUnit4ClassRunner::class) +class FactoryPackageTest : BaseHostJUnit4Test() { + + companion object { + private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app" + + private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk" + private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk" + private const val DEVICE_SIDE = "PackageManagerServiceDeviceSideTests.apk" + + @get:ClassRule + val deviceRebootRule = SystemPreparer.TestRuleDelegate(true) + } + + private val tempFolder = TemporaryFolder() + private val preparer: SystemPreparer = SystemPreparer(tempFolder, + SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device } + + @get:Rule + val rules = RuleChain.outerRule(tempFolder).around(preparer)!! + private val filePath = + HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.SYSTEM) + + @Before + @After + fun removeApk() { + device.uninstallPackage(TEST_PKG_NAME) + device.deleteFile(filePath.parent.toString()) + device.reboot() + } + + @Test + fun testGetInstalledPackagesFactoryOnlyFlag() { + // First, push a system app to the device and then update it so there's a data variant + preparer.pushResourceFile(VERSION_ONE, filePath.toString()) + .reboot() + + val versionTwoFile = HostUtils.copyResourceToHostFile(VERSION_TWO, tempFolder.newFile()) + + assertThat(device.installPackage(versionTwoFile, true)).isNull() + + runDeviceTest("testGetInstalledPackagesWithFactoryOnly") + } + + /** + * Run a device side test from com.android.server.pm.test.deviceside.DeviceSide + * + * @param method the method to run + */ + fun runDeviceTest(method: String) { + val deviceSideFile = HostUtils.copyResourceToHostFile(DEVICE_SIDE, tempFolder.newFile()) + assertThat(device.installPackage(deviceSideFile, true)).isNull() + runDeviceTests(device, "com.android.server.pm.test.deviceside", + "com.android.server.pm.test.deviceside.DeviceSide", method) + } +} diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp new file mode 100644 index 000000000000..af0ac77eaadd --- /dev/null +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp @@ -0,0 +1,33 @@ +// +// Copyright (C) 2019 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_helper_app { + name: "PackageManagerServiceDeviceSideTests", + sdk_version: "test_current", + srcs: ["src/**/*.kt"], + libs: [ + "android.test.base", + ], + static_libs: [ + "androidx.annotation_annotation", + "junit", + "junit-params", + "androidx.test.ext.junit", + "androidx.test.rules", + "truth-prebuilt", + ], + platform_apis: true, +} diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml new file mode 100644 index 000000000000..286ad56435fd --- /dev/null +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2019 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.server.pm.test.deviceside"> + + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" /> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.server.pm.test.deviceside" /> +</manifest> + diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/cts/test/deviceside/DeviceSide.kt b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/cts/test/deviceside/DeviceSide.kt new file mode 100644 index 000000000000..d140662a24c2 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/src/com/android/server/pm/cts/test/deviceside/DeviceSide.kt @@ -0,0 +1,42 @@ +package com.android.server.pm.test.deviceside + +import android.content.pm.PackageManager.MATCH_FACTORY_ONLY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.google.common.truth.Truth +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class DeviceSide { + companion object { + private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app" + } + + @Test + fun testGetInstalledPackagesWithFactoryOnly() { + val instrumentation = InstrumentationRegistry.getInstrumentation() + val uiAutomation = instrumentation.uiAutomation + val ctx = instrumentation.context + + uiAutomation.adoptShellPermissionIdentity() + try { + val packages1 = ctx.packageManager.getInstalledPackages(0) + .filter { it.packageName == TEST_PKG_NAME } + val packages2 = ctx.packageManager.getInstalledPackages(MATCH_FACTORY_ONLY) + .filter { it.packageName == TEST_PKG_NAME } + + Truth.assertWithMessage("Incorrect number of packages found") + .that(packages1.size).isEqualTo(1) + Truth.assertWithMessage("Incorrect number of packages found") + .that(packages2.size).isEqualTo(1) + + Truth.assertWithMessage("Incorrect version code for updated package") + .that(packages1[0].longVersionCode).isEqualTo(2) + Truth.assertWithMessage("Incorrect version code for factory package") + .that(packages2[0].longVersionCode).isEqualTo(1) + } finally { + uiAutomation.dropShellPermissionIdentity() + } + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java index 1cb004a6dc1e..fdcadf3e3088 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java @@ -25,6 +25,7 @@ import static android.location.Criteria.ACCURACY_COARSE; import static android.location.Criteria.ACCURACY_FINE; import static android.location.Criteria.POWER_HIGH; import static android.location.LocationManager.PASSIVE_PROVIDER; +import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; import static androidx.test.ext.truth.location.LocationSubject.assertThat; @@ -907,6 +908,21 @@ public class LocationProviderManagerTest { assertThat(mProvider.getRequest().interval).isEqualTo(5); } + @Test + public void testProviderRequest_BatterySaver_ScreenOnOff() { + mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode( + LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF); + + ILocationListener listener = createMockLocationListener(); + LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false); + mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener); + + assertThat(mProvider.getRequest().reportLocation).isTrue(); + + mInjector.getScreenInteractiveHelper().setScreenInteractive(false); + assertThat(mProvider.getRequest().reportLocation).isFalse(); + } + private ILocationListener createMockLocationListener() { return spy(new ILocationListener.Stub() { @Override diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-allowlist-format.xml index 597600303acb..597600303acb 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-whitelist-format.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/restrict-background-lists-allowlist-format.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-off.xml index 196ca28192e4..196ca28192e4 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-off.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-off.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-on.xml index 4b7724c05d8d..4b7724c05d8d 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-whitelisted-restrict-background-on.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-allowlisted-restrict-background-on.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-off.xml index 5b1c03ce170e..5b1c03ce170e 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-off.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-off.xml diff --git a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-on.xml index bec2371cff6f..bec2371cff6f 100644 --- a/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-blacklisted-restrict-background-on.xml +++ b/services/tests/servicestests/assets/NetworkPolicyManagerServiceTest/netpolicy/uidA-denylisted-restrict-background-on.xml diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java index 1b6ac3c84210..7d6d90c4578c 100644 --- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java @@ -26,7 +26,9 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.intThat; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -65,6 +67,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnit; @@ -277,7 +280,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128)); } @@ -290,7 +293,7 @@ public class VibratorServiceTest { assertTrue(service.isVibrating()); verify(mNativeWrapperMock).vibratorOff(); - verify(mNativeWrapperMock).vibratorOn(eq(100L)); + verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt()); } @@ -344,76 +347,157 @@ public class VibratorServiceTest { Mockito.clearInvocations(mNativeWrapperMock); VibrationEffect effect = VibrationEffect.createWaveform( - new long[] { 10, 10, 10 }, new int[] { 100, 200, 50 }, -1); + new long[]{10, 10, 10}, new int[]{100, 200, 50}, -1); vibrate(service, effect); verify(mNativeWrapperMock).vibratorOff(); + // Wait for VibrateThread to turn vibrator ON with total timing and no callback. Thread.sleep(5); - verify(mNativeWrapperMock).vibratorOn(eq(30L)); + verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull()); + + // First amplitude set right away. verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100)); + // Second amplitude set after first timing is finished. Thread.sleep(10); verify(mNativeWrapperMock).vibratorSetAmplitude(eq(200)); + // Third amplitude set after second timing is finished. Thread.sleep(10); verify(mNativeWrapperMock).vibratorSetAmplitude(eq(50)); } @Test - public void vibrate_withCallback_finishesVibrationWhenCallbackTriggered() { - mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() { + doAnswer(invocation -> { + ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + return null; + }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); + VibratorService service = createService(); + Mockito.clearInvocations(mNativeWrapperMock); + + vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); + + InOrder inOrderVerifier = inOrder(mNativeWrapperMock); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L), + any(VibratorService.Vibration.class)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + } + + @Test + public void vibrate_withOneShotAndNativeCallbackNotTriggered_finishesVibrationViaFallback() { VibratorService service = createService(); Mockito.clearInvocations(mNativeWrapperMock); + vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); + + verify(mNativeWrapperMock).vibratorOff(); + verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class)); + Mockito.clearInvocations(mNativeWrapperMock); + + // Run the scheduled callback to finish one-shot vibration. + mTestLooper.moveTimeForward(200); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).vibratorOff(); + } + + @Test + public void vibrate_withWaveformAndNativeCallback_callbackCannotBeTriggeredByNative() + throws Exception { + VibratorService service = createService(); + Mockito.clearInvocations(mNativeWrapperMock); + + VibrationEffect effect = VibrationEffect.createWaveform(new long[]{1, 3, 1, 2}, -1); + vibrate(service, effect); + + // Wait for VibrateThread to finish: 1ms OFF, 3ms ON, 1ms OFF, 2ms ON. + Thread.sleep(15); + InOrder inOrderVerifier = inOrder(mNativeWrapperMock); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull()); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull()); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + } + + @Test + public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() { + mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); doAnswer(invocation -> { ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); return null; }).when(mNativeWrapperMock).vibratorPerformComposedEffect( any(), any(VibratorService.Vibration.class)); + VibratorService service = createService(); + Mockito.clearInvocations(mNativeWrapperMock); - // Use vibration with delay so there is time for the callback to be triggered. VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) .compose(); vibrate(service, effect); - // Vibration canceled once before perform and once by native callback. - verify(mNativeWrapperMock, times(2)).vibratorOff(); - verify(mNativeWrapperMock).vibratorPerformComposedEffect( + InOrder inOrderVerifier = inOrder(mNativeWrapperMock); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( any(VibrationEffect.Composition.PrimitiveEffect[].class), any(VibratorService.Vibration.class)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @Test - public void vibrate_whenBinderDies_cancelsVibration() { + public void vibrate_withComposedAndNativeCallbackNotTriggered_finishesVibrationViaFallback() { mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); VibratorService service = createService(); Mockito.clearInvocations(mNativeWrapperMock); + VibrationEffect effect = VibrationEffect.startComposition() + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) + .compose(); + vibrate(service, effect); + + verify(mNativeWrapperMock).vibratorOff(); + verify(mNativeWrapperMock).vibratorPerformComposedEffect( + any(VibrationEffect.Composition.PrimitiveEffect[].class), + any(VibratorService.Vibration.class)); + Mockito.clearInvocations(mNativeWrapperMock); + + // Run the scheduled callback to finish one-shot vibration. + mTestLooper.moveTimeForward(10000); // 10s + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).vibratorOff(); + } + + @Test + public void vibrate_whenBinderDies_cancelsVibration() { + mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); doAnswer(invocation -> { ((VibratorService.Vibration) invocation.getArgument(1)).binderDied(); return null; }).when(mNativeWrapperMock).vibratorPerformComposedEffect( any(), any(VibratorService.Vibration.class)); + VibratorService service = createService(); + Mockito.clearInvocations(mNativeWrapperMock); - // Use vibration with delay so there is time for the callback to be triggered. VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10) .compose(); vibrate(service, effect); - // Vibration canceled once before perform and once by native binder death. - verify(mNativeWrapperMock, times(2)).vibratorOff(); - verify(mNativeWrapperMock).vibratorPerformComposedEffect( + InOrder inOrderVerifier = inOrder(mNativeWrapperMock); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); + inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect( any(VibrationEffect.Composition.PrimitiveEffect[].class), any(VibratorService.Vibration.class)); + inOrderVerifier.verify(mNativeWrapperMock).vibratorOff(); } @Test public void cancelVibrate_withDeviceVibrating_callsVibratorOff() { VibratorService service = createService(); - vibrate(service, VibrationEffect.createOneShot(100, 128)); + vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE)); assertTrue(service.isVibrating()); Mockito.clearInvocations(mNativeWrapperMock); @@ -434,18 +518,20 @@ public class VibratorServiceTest { @Test public void registerVibratorStateListener_callbacksAreTriggered() throws Exception { + doAnswer(invocation -> { + ((VibratorService.Vibration) invocation.getArgument(1)).onComplete(); + return null; + }).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class)); VibratorService service = createService(); service.registerVibratorStateListener(mVibratorStateListenerMock); verify(mVibratorStateListenerMock).onVibrating(false); + Mockito.clearInvocations(mVibratorStateListenerMock); vibrate(service, VibrationEffect.createOneShot(10, VibrationEffect.DEFAULT_AMPLITUDE)); - verify(mVibratorStateListenerMock).onVibrating(true); - - // Run the scheduled callback to finish one-shot vibration. - mTestLooper.moveTimeForward(10); - mTestLooper.dispatchAll(); - verify(mVibratorStateListenerMock, times(2)).onVibrating(false); + InOrder inOrderVerifier = inOrder(mVibratorStateListenerMock); + inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(true)); + inOrderVerifier.verify(mVibratorStateListenerMock).onVibrating(eq(false)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 9a465a91e84e..8fc228734f37 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1604,7 +1604,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.setApplicationRestrictionsManagingPackage(admin1, RESTRICTIONS_DELEGATE); // DPMS correctly stores and retrieves the delegates - DevicePolicyManagerService.DevicePolicyData policy = dpms.mUserData.get(userHandle); + DevicePolicyData policy = dpms.mUserData.get(userHandle); assertEquals(2, policy.mDelegationMap.size()); MoreAsserts.assertContentsInAnyOrder(policy.mDelegationMap.get(CERT_DELEGATE), DELEGATION_CERT_INSTALL); @@ -1846,11 +1846,11 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(getServices().userManagerInternal); } - private DevicePolicyManagerService.ActiveAdmin getDeviceOwner() { + private ActiveAdmin getDeviceOwner() { ComponentName component = dpms.mOwners.getDeviceOwnerComponent(); - DevicePolicyManagerService.DevicePolicyData policy = + DevicePolicyData policy = dpms.getUserData(dpms.mOwners.getDeviceOwnerUserId()); - for (DevicePolicyManagerService.ActiveAdmin admin : policy.mAdminList) { + for (ActiveAdmin admin : policy.mAdminList) { if (component.equals(admin.info.getComponent())) { return admin; } @@ -3745,8 +3745,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM - DevicePolicyManagerService.DevicePolicyData userData = - new DevicePolicyManagerService.DevicePolicyData(userId); + DevicePolicyData userData = new DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); @@ -3770,8 +3769,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { setUserSetupCompleteForUser(false, userId); // GIVEN userComplete is true in DPM - DevicePolicyManagerService.DevicePolicyData userData = - new DevicePolicyManagerService.DevicePolicyData(userId); + DevicePolicyData userData = new DevicePolicyData(userId); userData.mUserSetupComplete = true; dpms.mUserData.put(UserHandle.USER_SYSTEM, userData); 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/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 12b144f2b778..1f66c7c02658 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -129,7 +129,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID); // verify credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - firstUnifiedPassword, 0, PRIMARY_USER_ID) + firstUnifiedPassword, PRIMARY_USER_ID, 0 /* flags */) .getResponseCode()); // Verify that we have a new auth token for the profile @@ -186,13 +186,13 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID); // verify primary credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - primaryPassword, 0, PRIMARY_USER_ID) + primaryPassword, PRIMARY_USER_ID, 0 /* flags */) .getResponseCode()); assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); // verify profile credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword, 0, MANAGED_PROFILE_USER_ID) + profilePassword, MANAGED_PROFILE_USER_ID, 0 /* flags */) .getResponseCode()); assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); @@ -203,7 +203,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { newPassword("pwd"), primaryPassword, PRIMARY_USER_ID)); mStorageManager.setIgnoreBadUnlock(false); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword, 0, MANAGED_PROFILE_USER_ID) + profilePassword, MANAGED_PROFILE_USER_ID, 0 /* flags */) .getResponseCode()); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); } @@ -389,7 +389,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { initializeStorageWithCredential(PRIMARY_USER_ID, password, 1234); reset(mRecoverableKeyStoreManager); - mService.verifyCredential(password, 1, PRIMARY_USER_ID); + mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */); verify(mRecoverableKeyStoreManager) .lockScreenSecretAvailable( @@ -406,7 +406,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { MANAGED_PROFILE_USER_ID)); reset(mRecoverableKeyStoreManager); - mService.verifyCredential(pattern, 1, MANAGED_PROFILE_USER_ID); + mService.verifyCredential(pattern, MANAGED_PROFILE_USER_ID, 0 /* flags */); verify(mRecoverableKeyStoreManager) .lockScreenSecretAvailable( @@ -421,7 +421,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); reset(mRecoverableKeyStoreManager); - mService.verifyCredential(pattern, 1, PRIMARY_USER_ID); + mService.verifyCredential(pattern, PRIMARY_USER_ID, 0 /* flags */); // Parent sends its credentials for both the parent and profile. verify(mRecoverableKeyStoreManager) @@ -484,9 +484,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { private void assertVerifyCredentials(int userId, LockscreenCredential credential, long sid) throws RemoteException{ - final long challenge = 54321; - VerifyCredentialResponse response = mService.verifyCredential(credential, - challenge, userId); + VerifyCredentialResponse response = mService.verifyCredential(credential, userId, + 0 /* flags */); assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode()); if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId)); @@ -508,7 +507,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { badCredential = LockscreenCredential.createPin("0"); } assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential( - badCredential, challenge, userId).getResponseCode()); + badCredential, userId, 0 /* flags */).getResponseCode()); } private void initializeStorageWithCredential(int userId, LockscreenCredential credential, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java index 4b3f7b5d08ef..9c0239b2b6a6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java @@ -52,7 +52,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @Test @@ -61,7 +62,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPattern("4321"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPattern("4321"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @Test @@ -70,7 +72,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPassword("4321"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPassword("4321"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @Test @@ -80,7 +83,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PATTERN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPattern("5678"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPattern("5678"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @Test @@ -98,7 +102,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { mSettings.setDeviceProvisioned(true); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, - mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @Test @@ -113,7 +118,8 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PIN, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */) + .getResponseCode()); } @@ -129,6 +135,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests { assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP)); assertEquals(VerifyCredentialResponse.RESPONSE_OK, - mService.verifyCredential(newPin("1234"), 0, USER_FRP).getResponseCode()); + mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */) + .getResponseCode()); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index ba851992cbad..2bd0e55f7d21 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -119,8 +119,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); mService.setLockCredential(newPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); + newPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } @@ -131,12 +130,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); + password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - badPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); + badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); } @Test @@ -153,8 +150,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { // set a new password mService.setLockCredential(badPassword, nonePassword(), PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - badPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); + badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } @@ -166,8 +162,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); mService.setLockCredential(badPassword, password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - badPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); + badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); // Check the same secret was passed each time ArgumentCaptor<ArrayList<Byte>> secret = ArgumentCaptor.forClass(ArrayList.class); @@ -183,8 +178,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); reset(mAuthSecretService); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); + password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class)); } @@ -194,8 +188,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, SECONDARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, SECONDARY_USER_ID) - .getResponseCode()); + password, SECONDARY_USER_ID, 0 /* flags */).getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); } @@ -246,7 +239,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID)); - mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); + mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */) + .getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID)); @@ -259,8 +253,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { verify(mDevicePolicyManager).reportPasswordChanged(PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - pattern, 0, PRIMARY_USER_ID) - .getResponseCode()); + pattern, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } @@ -275,7 +268,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); + mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */) + .getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mLocalService.setLockCredentialWithToken(nonePassword(), handle, token, PRIMARY_USER_ID); @@ -284,8 +278,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - pattern, 0, PRIMARY_USER_ID) - .getResponseCode()); + pattern, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } @@ -301,7 +294,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); + mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */) + .getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.setLockCredential(pattern, password, PRIMARY_USER_ID); @@ -309,8 +303,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { mLocalService.setLockCredentialWithToken(newPassword, handle, token, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, 0, PRIMARY_USER_ID) - .getResponseCode()); + newPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } @@ -357,8 +350,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); // Activate token (password gets migrated to SP at the same time) assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); + password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); // Verify token is activated assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); } @@ -488,8 +480,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, 0, PRIMARY_USER_ID) - .getResponseCode()); + password, PRIMARY_USER_ID, 0 /* flags */).getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); } @@ -503,7 +494,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { reset(mDevicePolicyManager); long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); - mService.verifyCredential(password, 0, PRIMARY_USER_ID).getResponseCode(); + mService.verifyCredential(password, PRIMARY_USER_ID, 0 /* flags */) + .getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mService.onCleanupUser(PRIMARY_USER_ID); diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 128177b073b0..58b71d4b702a 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -462,7 +462,7 @@ public class NetworkPolicyManagerServiceTest { @Test public void testTurnRestrictBackgroundOn() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. + assertRestrictBackgroundOff(); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(true); assertRestrictBackgroundChangedReceived(futureIntent, null); @@ -471,7 +471,7 @@ public class NetworkPolicyManagerServiceTest { @Test @NetPolicyXml("restrict-background-on.xml") public void testTurnRestrictBackgroundOff() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(false); @@ -479,28 +479,27 @@ public class NetworkPolicyManagerServiceTest { } /** - * Adds whitelist when restrict background is on - app should receive an intent. + * Adds allowlist when restrict background is on - app should receive an intent. */ @Test @NetPolicyXml("restrict-background-on.xml") - public void testAddRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + public void testAddRestrictBackgroundAllowlist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - addRestrictBackgroundWhitelist(true); + addRestrictBackgroundAllowlist(true); } /** - * Adds whitelist when restrict background is off - app should not receive an intent. + * Adds allowlist when restrict background is off - app should not receive an intent. */ @Test - public void testAddRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - addRestrictBackgroundWhitelist(false); + public void testAddRestrictBackgroundAllowlist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + addRestrictBackgroundAllowlist(false); } - private void addRestrictBackgroundWhitelist(boolean expectIntent) throws Exception { - // Sanity checks. - assertWhitelistUids(); + private void addRestrictBackgroundAllowlist(boolean expectIntent) throws Exception { + assertAllowlistUids(); assertUidPolicy(UID_A, POLICY_NONE); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); @@ -508,7 +507,7 @@ public class NetworkPolicyManagerServiceTest { mService.setUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); mPolicyListener.waitAndVerify() .onUidPoliciesChanged(APP_ID_A, POLICY_ALLOW_METERED_BACKGROUND); @@ -520,24 +519,24 @@ public class NetworkPolicyManagerServiceTest { } /** - * Removes whitelist when restrict background is on - app should receive an intent. + * Removes allowlist when restrict background is on - app should receive an intent. */ @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testRemoveRestrictBackgroundAllowlist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - removeRestrictBackgroundWhitelist(true); + removeRestrictBackgroundAllowlist(true); } /** - * Removes whitelist when restrict background is off - app should not receive an intent. + * Removes allowlist when restrict background is off - app should not receive an intent. */ @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-off.xml") - public void testRemoveRestrictBackgroundWhitelist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - removeRestrictBackgroundWhitelist(false); + @NetPolicyXml("uidA-allowlisted-restrict-background-off.xml") + public void testRemoveRestrictBackgroundAllowlist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + removeRestrictBackgroundAllowlist(false); } @Test @@ -688,9 +687,8 @@ public class NetworkPolicyManagerServiceTest { assertFalse(mService.getRestrictBackground()); } - private void removeRestrictBackgroundWhitelist(boolean expectIntent) throws Exception { - // Sanity checks. - assertWhitelistUids(UID_A); + private void removeRestrictBackgroundAllowlist(boolean expectIntent) throws Exception { + assertAllowlistUids(UID_A); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); @@ -698,7 +696,7 @@ public class NetworkPolicyManagerServiceTest { mService.setUidPolicy(UID_A, POLICY_NONE); - assertWhitelistUids(); + assertAllowlistUids(); assertUidPolicy(UID_A, POLICY_NONE); mPolicyListener.waitAndVerify().onUidPoliciesChanged(APP_ID_A, POLICY_NONE); if (expectIntent) { @@ -709,27 +707,27 @@ public class NetworkPolicyManagerServiceTest { } /** - * Adds blacklist when restrict background is on - app should not receive an intent. + * Adds denylist when restrict background is on - app should not receive an intent. */ @Test @NetPolicyXml("restrict-background-on.xml") - public void testAddRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + public void testAddRestrictBackgroundDenylist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - addRestrictBackgroundBlacklist(false); + addRestrictBackgroundDenylist(false); } /** - * Adds blacklist when restrict background is off - app should receive an intent. + * Adds denylist when restrict background is off - app should receive an intent. */ @Test - public void testAddRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - addRestrictBackgroundBlacklist(true); + public void testAddRestrictBackgroundDenylist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + addRestrictBackgroundDenylist(true); } - private void addRestrictBackgroundBlacklist(boolean expectIntent) throws Exception { - assertUidPolicy(UID_A, POLICY_NONE); // Sanity check. + private void addRestrictBackgroundDenylist(boolean expectIntent) throws Exception { + assertUidPolicy(UID_A, POLICY_NONE); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt()); @@ -746,28 +744,28 @@ public class NetworkPolicyManagerServiceTest { } /** - * Removes blacklist when restrict background is on - app should not receive an intent. + * Removes denylist when restrict background is on - app should not receive an intent. */ @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml") - public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOn() throws Exception { - assertRestrictBackgroundOn(); // Sanity check. + @NetPolicyXml("uidA-denylisted-restrict-background-on.xml") + public void testRemoveRestrictBackgroundDenylist_restrictBackgroundOn() throws Exception { + assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - removeRestrictBackgroundBlacklist(false); + removeRestrictBackgroundDenylist(false); } /** - * Removes blacklist when restrict background is off - app should receive an intent. + * Removes denylist when restrict background is off - app should receive an intent. */ @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-off.xml") - public void testRemoveRestrictBackgroundBlacklist_restrictBackgroundOff() throws Exception { - assertRestrictBackgroundOff(); // Sanity check. - removeRestrictBackgroundBlacklist(true); + @NetPolicyXml("uidA-denylisted-restrict-background-off.xml") + public void testRemoveRestrictBackgroundDenylist_restrictBackgroundOff() throws Exception { + assertRestrictBackgroundOff(); + removeRestrictBackgroundDenylist(true); } - private void removeRestrictBackgroundBlacklist(boolean expectIntent) throws Exception { - assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); // Sanity check. + private void removeRestrictBackgroundDenylist(boolean expectIntent) throws Exception { + assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mPolicyListener.expect().onUidPoliciesChanged(anyInt(), anyInt()); @@ -784,9 +782,8 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-blacklisted-restrict-background-on.xml") - public void testBlacklistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-denylisted-restrict-background-on.xml") + public void testDenylistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); assertUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); @@ -797,12 +794,11 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testWhitelistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testAllowlistedAppIsNotNotifiedWhenRestrictBackgroundIsOn() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); setRestrictBackground(true); @@ -810,12 +806,11 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("uidA-whitelisted-restrict-background-on.xml") - public void testWhitelistedAppIsNotifiedWhenBlacklisted() throws Exception { - // Sanity checks. + @NetPolicyXml("uidA-allowlisted-restrict-background-on.xml") + public void testAllowlistedAppIsNotifiedWhenDenylisted() throws Exception { assertRestrictBackgroundOn(); assertRestrictBackgroundChangedReceived(mFutureIntent, null); - assertWhitelistUids(UID_A); + assertAllowlistUids(UID_A); final FutureIntent futureIntent = newRestrictBackgroundChangedFuture(); mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND); @@ -823,8 +818,8 @@ public class NetworkPolicyManagerServiceTest { } @Test - @NetPolicyXml("restrict-background-lists-whitelist-format.xml") - public void testRestrictBackgroundLists_whitelistFormat() throws Exception { + @NetPolicyXml("restrict-background-lists-allowlist-format.xml") + public void testRestrictBackgroundLists_allowlistFormat() throws Exception { restrictBackgroundListsTest(); } @@ -835,33 +830,33 @@ public class NetworkPolicyManagerServiceTest { } private void restrictBackgroundListsTest() throws Exception { - // UIds that are whitelisted. - assertWhitelistUids(UID_A, UID_B, UID_C); + // UIds that are allowlisted. + assertAllowlistUids(UID_A, UID_B, UID_C); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_B, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_C, POLICY_ALLOW_METERED_BACKGROUND); - // UIDs that are blacklisted. + // UIDs that are denylisted. assertUidPolicy(UID_D, POLICY_NONE); assertUidPolicy(UID_E, POLICY_REJECT_METERED_BACKGROUND); // UIDS that have legacy policies. assertUidPolicy(UID_F, 2); // POLICY_ALLOW_BACKGROUND_BATTERY_SAVE - // Remove whitelist. + // Remove allowlist. mService.setUidPolicy(UID_A, POLICY_NONE); assertUidPolicy(UID_A, POLICY_NONE); - assertWhitelistUids(UID_B, UID_C); + assertAllowlistUids(UID_B, UID_C); - // Add whitelist when blacklisted. + // Add allowlist when denylisted. mService.setUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND); assertUidPolicy(UID_E, POLICY_ALLOW_METERED_BACKGROUND); - assertWhitelistUids(UID_B, UID_C, UID_E); + assertAllowlistUids(UID_B, UID_C, UID_E); - // Add blacklist when whitelisted. + // Add denylist when allowlisted. mService.setUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); - assertWhitelistUids(UID_C, UID_E); + assertAllowlistUids(UID_C, UID_E); } /** @@ -870,9 +865,9 @@ public class NetworkPolicyManagerServiceTest { @Test @NetPolicyXml("restrict-background-lists-mixed-format.xml") public void testRestrictBackgroundLists_mixedFormat() throws Exception { - assertWhitelistUids(UID_A, UID_C, UID_D); + assertAllowlistUids(UID_A, UID_C, UID_D); assertUidPolicy(UID_A, POLICY_ALLOW_METERED_BACKGROUND); - assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); // Blacklist prevails. + assertUidPolicy(UID_B, POLICY_REJECT_METERED_BACKGROUND); // Denylist prevails. assertUidPolicy(UID_C, (POLICY_ALLOW_METERED_BACKGROUND | 2)); assertUidPolicy(UID_D, POLICY_ALLOW_METERED_BACKGROUND); } @@ -2045,7 +2040,7 @@ public class NetworkPolicyManagerServiceTest { } } - private void assertWhitelistUids(int... uids) { + private void assertAllowlistUids(int... uids) { assertContainsInAnyOrder(mService.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND), uids); } @@ -2133,7 +2128,6 @@ public class NetworkPolicyManagerServiceTest { private void setRestrictBackground(boolean flag) throws Exception { mService.setRestrictBackground(flag); - // Sanity check. assertEquals("restrictBackground not set", flag, mService.getRestrictBackground()); } 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/Android.bp b/services/tests/wmtests/Android.bp index b3d75d31cb60..4ca5b9e4b14f 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -2,15 +2,37 @@ // Build WmTests package //######################################################################## +// Include all test java files. +filegroup { + name: "wmtests-sources", + srcs: [ + "src/**/*.java", + ], +} + +genrule { + name: "wmtests.protologsrc", + srcs: [ + ":protolog-groups", + ":wmtests-sources", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) transform-protolog-calls " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + + "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + + "--output-srcjar $(out) " + + "$(locations :wmtests-sources)", + out: ["wmtests.protolog.srcjar"], +} + android_test { name: "WmTests", // We only want this apk build for tests. - - // Include all test java files. - srcs: [ - "src/**/*.java", - ], + srcs: [":wmtests.protologsrc"], static_libs: [ "frameworks-base-testutils", 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 6061f13fcee5..f860e174fd15 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1506,7 +1506,7 @@ public class ActivityRecordTests extends WindowTestsBase { final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; - final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( + final TestWindowState w = new TestWindowState( mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity); mActivity.addWindow(w); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index 2e988af29638..567610018fc1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -225,5 +225,27 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { mockSession.finishMocking(); } + + @Test + public void testResumeNextActivityOnCrashedAppDied() { + mSupervisor.beginDeferResume(); + final ActivityRecord homeActivity = new ActivityBuilder(mAtm) + .setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()) + .build(); + final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); + mSupervisor.endDeferResume(); + // Assume the activity is finishing and hidden because it was crashed. + activity.finishing = true; + activity.mVisibleRequested = false; + activity.setVisible(false); + activity.getRootTask().mPausingActivity = activity; + homeActivity.setState(Task.ActivityState.PAUSED, "test"); + + // Even the visibility states are invisible, the next activity should be resumed because + // the crashed activity was pausing. + mAtm.mInternal.handleAppDied(activity.app, false /* restarting */, + null /* finishInstrumentationCallback */); + assertEquals(Task.ActivityState.RESUMED, homeActivity.getState()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 7adceade0b9b..1b2192035213 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -133,10 +133,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; @@ -162,13 +162,13 @@ public class AppTransitionControllerTest extends WindowTestsBase { // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (closing, invisible) // +- [TaskStack2] - [Task2] - [ActivityRecord2] (opening, visible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); activity1.setVisible(true); activity1.mVisibleRequested = true; activity1.mRequestForceTransition = true; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; activity2.mRequestForceTransition = true; @@ -193,10 +193,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { @Test public void testGetAnimationTargets_exitingBeforeTransition() { // Create another non-empty task so the animation target won't promote to task display area. - WindowTestUtils.createTestActivityRecord( + createTestActivityRecord( mDisplayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); final Task stack = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(stack); + final ActivityRecord activity = createTestActivityRecord(stack); activity.setVisible(false); activity.mIsExiting = true; @@ -218,20 +218,20 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible) // +- [AppWindow2] (being-replaced) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1); + final ActivityRecord activity1 = createTestActivityRecord(stack1); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow1"); - final WindowTestUtils.TestWindowState appWindow1 = createWindowState(attrs, activity1); + final TestWindowState appWindow1 = createWindowState(attrs, activity1); appWindow1.mWillReplaceWindow = true; activity1.addWindow(appWindow1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2); + final ActivityRecord activity2 = createTestActivityRecord(stack2); activity2.setVisible(false); activity2.mVisibleRequested = false; attrs.setTitle("AppWindow2"); - final WindowTestUtils.TestWindowState appWindow2 = createWindowState(attrs, activity2); + final TestWindowState appWindow2 = createWindowState(attrs, activity2); appWindow2.mWillReplaceWindow = true; activity2.addWindow(appWindow2); @@ -262,21 +262,17 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [ActivityRecord4] (invisible) final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); activity2.setVisible(false); activity2.mVisibleRequested = false; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); activity4.setVisible(false); activity4.mVisibleRequested = false; @@ -303,12 +299,10 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [ActivityRecord2] (closing, visible) final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); activity1.setVisible(false); activity1.mVisibleRequested = true; - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -337,22 +331,18 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; activity1.setOccludesParent(false); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); activity3.setOccludesParent(false); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -381,24 +371,20 @@ public class AppTransitionControllerTest extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; activity1.setOccludesParent(false); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task1); activity2.setVisible(false); activity2.mVisibleRequested = true; final Task stack2 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskInStack(stack2, 0 /* userId */); - final ActivityRecord activity3 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task2); activity3.setOccludesParent(false); - final ActivityRecord activity4 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity4 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); @@ -425,13 +411,11 @@ public class AppTransitionControllerTest extends WindowTestsBase { // +- [Task2] - [ActivityRecord2] (closing, visible) final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task1); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); activity1.setVisible(false); activity1.mVisibleRequested = true; final Task task2 = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask( - mDisplayContent, task2); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2); final ArraySet<ActivityRecord> opening = new ArraySet<>(); opening.add(activity1); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 17914e7fb68c..ee030af36b8f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -151,8 +151,7 @@ public class AppTransitionTests extends WindowTestsBase { final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(dc1); + final ActivityRecord activity1 = createTestActivityRecord(dc1); task1.addChild(activity1, 0); // Simulate same app is during opening / closing transition set stage. diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 888935ef9747..085b8dec2cb7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -92,7 +92,7 @@ public class AppWindowTokenTests extends WindowTestsBase { public void setUp() throws Exception { mStack = createTaskStackOnDisplay(mDisplayContent); mTask = createTaskInStack(mStack, 0 /* userId */); - mActivity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + mActivity = createTestActivityRecord(mDisplayContent); mTask.addChild(mActivity, 0); } @@ -165,7 +165,7 @@ public class AppWindowTokenTests extends WindowTestsBase { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("AppWindow"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); mActivity.addWindow(appWindow); // Set initial orientation and update. @@ -198,7 +198,7 @@ public class AppWindowTokenTests extends WindowTestsBase { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( TYPE_BASE_APPLICATION); attrs.setTitle("RotationByPolicy"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); mActivity.addWindow(appWindow); // Set initial orientation and update. @@ -244,7 +244,7 @@ public class AppWindowTokenTests extends WindowTestsBase { TYPE_BASE_APPLICATION); attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD; attrs.setTitle("AppWindow"); - final WindowTestUtils.TestWindowState appWindow = createWindowState(attrs, mActivity); + final TestWindowState appWindow = createWindowState(attrs, mActivity); // Add window with show when locked flag mActivity.addWindow(appWindow); @@ -307,7 +307,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation); assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation); - final ActivityRecord topActivity = WindowTestUtils.createTestActivityRecord(mStack); + final ActivityRecord topActivity = createTestActivityRecord(mStack); topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation); @@ -490,8 +490,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } private ActivityRecord createTestActivityRecordForGivenTask(Task task) { - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); task.addChild(activity, 0); waitUntilHandlersIdle(); return activity; @@ -562,7 +561,7 @@ public class AppWindowTokenTests extends WindowTestsBase { public void testHasStartingWindow() { final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING); - final WindowTestUtils.TestWindowState startingWindow = createWindowState(attrs, mActivity); + final TestWindowState startingWindow = createWindowState(attrs, mActivity); mActivity.startingDisplayed = true; mActivity.addWindow(startingWindow); assertTrue("Starting window should be present", mActivity.hasStartingWindow()); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 0cc61599c2ac..d54b4a0a72f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -326,7 +326,7 @@ public class DisplayContentTests extends WindowTestsBase { assertEquals(dc, stack.getDisplayContent()); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(dc); + final ActivityRecord activity = createTestActivityRecord(dc); task.addChild(activity, 0); assertEquals(dc, task.getDisplayContent()); assertEquals(dc, activity.getDisplayContent()); @@ -397,16 +397,14 @@ public class DisplayContentTests extends WindowTestsBase { // Add stack with activity. final Task stack0 = createTaskStackOnDisplay(dc0); final Task task0 = createTaskInStack(stack0, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(dc0); + final ActivityRecord activity = createTestActivityRecord(dc0); task0.addChild(activity, 0); dc0.configureDisplayPolicy(); assertNotNull(dc0.mTapDetector); final Task stack1 = createTaskStackOnDisplay(dc1); final Task task1 = createTaskInStack(stack1, 0 /* userId */); - final ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(dc0); + final ActivityRecord activity1 = createTestActivityRecord(dc0); task1.addChild(activity1, 0); dc1.configureDisplayPolicy(); assertNotNull(dc1.mTapDetector); @@ -1296,7 +1294,7 @@ public class DisplayContentTests extends WindowTestsBase { final ActivityRecord pinnedActivity = createActivityRecord(displayContent, WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); final Task pinnedTask = pinnedActivity.getRootTask(); - final ActivityRecord homeActivity = WindowTestUtils.createTestActivityRecord( + final ActivityRecord homeActivity = createTestActivityRecord( displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask()); if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 4ea5b97decf4..0675c6d04422 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -48,12 +48,14 @@ import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT; import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -874,6 +876,19 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + public void testFixedRotationInsetsSourceFrame() { + mDisplayPolicy.beginLayoutLw(mFrames, mDisplayContent.getConfiguration().uiMode); + doReturn((mDisplayContent.getRotation() + 1) % 4).when(mDisplayContent) + .rotationForActivityInDifferentOrientation(eq(mWindow.mActivityRecord)); + final Rect frame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + mDisplayContent.rotateInDifferentOrientationIfNeeded(mWindow.mActivityRecord); + final Rect rotatedFrame = mWindow.getInsetsState().getSource(ITYPE_STATUS_BAR).getFrame(); + + assertEquals(DISPLAY_WIDTH, frame.width()); + assertEquals(DISPLAY_HEIGHT, rotatedFrame.width()); + } + + @Test public void testScreenDecorWindows() { final WindowState decorWindow = spy( createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow")); diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index e18d93d82686..45369975fcc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -95,8 +95,7 @@ public class DragDropControllerTests extends WindowTestsBase { * Creates a window state which can be used as a drop target. */ private WindowState createDropTargetWindow(String name, int ownerId) { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord( - mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, ownerId); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index 5e83e66536ed..085230d35c6a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -28,6 +28,9 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -40,6 +43,7 @@ import static org.mockito.Mockito.verify; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; +import android.util.IntArray; import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.test.InsetsModeSession; @@ -328,6 +332,27 @@ public class InsetsStateControllerTest extends WindowTestsBase { assertNull(getController().getControlsForDispatch(app)); } + @Test + public void testTransientVisibilityOfFixedRotationState() { + final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final InsetsSourceProvider provider = getController().getSourceProvider(ITYPE_STATUS_BAR); + provider.setWindow(statusBar, null, null); + + final InsetsState rotatedState = new InsetsState(app.getInsetsState(), + true /* copySources */); + spyOn(app.mToken); + doReturn(rotatedState).when(app.mToken).getFixedRotationTransformInsetsState(); + assertTrue(rotatedState.getSource(ITYPE_STATUS_BAR).isVisible()); + + provider.getSource().setVisible(false); + mDisplayContent.getInsetsPolicy().showTransient( + IntArray.wrap(new int[] { ITYPE_STATUS_BAR })); + + assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR)); + assertFalse(app.getInsetsState().getSource(ITYPE_STATUS_BAR).isVisible()); + } + private InsetsStateController getController() { return mDisplayContent.getInsetsStateController(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java index d1510cf811fb..8223024234fb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java @@ -25,9 +25,12 @@ import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; -import com.android.server.protolog.ProtoLogImpl; +import com.android.internal.protolog.ProtoLogGroup; +import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.ProtoLog; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; /** @@ -35,6 +38,7 @@ import org.junit.Test; */ @SmallTest @Presubmit +@Ignore("b/163095037") public class ProtoLogIntegrationTest { @After public void tearDown() { @@ -44,17 +48,21 @@ public class ProtoLogIntegrationTest { @Test public void testProtoLogToolIntegration() { ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); - runWith(mockedProtoLog, () -> { - ProtoLogGroup.testProtoLog(); - }); + runWith(mockedProtoLog, this::testProtoLog); verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP), anyInt(), eq(0b0010101001010111), - eq(ProtoLogGroup.TEST_GROUP.isLogToLogcat() + eq(com.android.internal.protolog.ProtoLogGroup.TEST_GROUP.isLogToLogcat() ? "Test completed successfully: %b %d %o %x %e %g %f %% %s" : null), eq(new Object[]{true, 1L, 2L, 3L, 0.4, 0.5, 0.6, "ok"})); } + private void testProtoLog() { + ProtoLog.e(ProtoLogGroup.TEST_GROUP, + "Test completed successfully: %b %d %o %x %e %g %f %% %s.", + true, 1, 2, 3, 0.4, 0.5, 0.6, "ok"); + } + /** * Starts protolog for the duration of {@code runnable}, with a ProtoLogImpl instance installed. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 0e1d4dc4aa0d..982e469cba92 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -568,7 +568,9 @@ public class SizeCompatTests extends WindowTestsBase { private static WindowState addWindowToActivity(ActivityRecord activity) { final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; - final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( + params.setFitInsetsSides(0); + params.setFitInsetsTypes(0); + final TestWindowState w = new TestWindowState( activity.mWmService, mock(Session.class), new TestIWindow(), params, activity); WindowTestsBase.makeWindowVisible(w); w.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; @@ -581,7 +583,7 @@ public class SizeCompatTests extends WindowTestsBase { doReturn(true).when(displayPolicy).hasStatusBar(); displayPolicy.onConfigurationChanged(); - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken( + final TestWindowToken token = createTestWindowToken( WindowManager.LayoutParams.TYPE_STATUS_BAR, displayContent); final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_STATUS_BAR); @@ -589,7 +591,7 @@ public class SizeCompatTests extends WindowTestsBase { attrs.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; attrs.setFitInsetsTypes(0 /* types */); - final WindowTestUtils.TestWindowState statusBar = new WindowTestUtils.TestWindowState( + final TestWindowState statusBar = new TestWindowState( displayContent.mWmService, mock(Session.class), new TestIWindow(), attrs, token); token.addWindow(statusBar); statusBar.setRequestedSize(displayContent.mBaseDisplayWidth, diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index 3492556b3682..260f1e9a9259 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -76,8 +76,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { // Stack should contain visible app window to be considered visible. final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */); assertFalse(mPinnedStack.isVisible()); - final ActivityRecord pinnedApp = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord pinnedApp = createTestActivityRecord(mDisplayContent); pinnedTask.addChild(pinnedApp, 0 /* addPos */); assertTrue(mPinnedStack.isVisible()); } @@ -92,7 +91,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final Task stack = createTaskStackOnDisplay( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); task.addChild(activity, 0 /* addPos */); final TaskDisplayArea taskDisplayArea = activity.getDisplayArea(); activity.mNeedsAnimationBoundsLayer = true; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java index 205b842253b7..7cf30c0c9f35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java @@ -85,14 +85,12 @@ public class TaskStackTests extends WindowTestsBase { public void testClosingAppDifferentStackOrientation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); task1.addChild(activity1, 0); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - ActivityRecord activity2= - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task2.addChild(activity2, 0); activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); @@ -105,14 +103,12 @@ public class TaskStackTests extends WindowTestsBase { public void testMoveTaskToBackDifferentStackOrientation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); task1.addChild(activity1, 0); activity1.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); final Task task2 = createTaskInStack(stack, 1 /* userId */); - ActivityRecord activity2 = - WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task2.addChild(activity2, 0); activity2.setOrientation(SCREEN_ORIENTATION_PORTRAIT); assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation()); @@ -221,7 +217,7 @@ public class TaskStackTests extends WindowTestsBase { public void testActivityAndTaskGetsProperType() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task1 = createTaskInStack(stack, 0 /* userId */); - ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); // First activity should become standard task1.addChild(activity1, 0); @@ -229,7 +225,7 @@ public class TaskStackTests extends WindowTestsBase { assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); // Second activity should also become standard - ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); task1.addChild(activity2, WindowContainer.POSITION_TOP); assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, activity2.getActivityType()); assertEquals(WindowConfiguration.ACTIVITY_TYPE_STANDARD, task1.getActivityType()); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 92b6e6ef8ec9..ace0400bc293 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -56,8 +56,7 @@ public class TaskTests extends WindowTestsBase { public void testRemoveContainer() { final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); task.removeIfPossible(); // Assert that the container was removed. @@ -70,8 +69,7 @@ public class TaskTests extends WindowTestsBase { public void testRemoveContainer_deferRemoval() { final Task stackController1 = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stackController1, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); doReturn(true).when(task).shouldDeferRemoval(); @@ -153,10 +151,8 @@ public class TaskTests extends WindowTestsBase { public void testIsInStack() { final Task task1 = createTaskStackOnDisplay(mDisplayContent); final Task task2 = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task1); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task2); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task1); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task2); assertEquals(activity1, task1.isInTask(activity1)); assertNull(task1.isInTask(activity2)); } @@ -165,12 +161,9 @@ public class TaskTests extends WindowTestsBase { public void testRemoveChildForOverlayTask() { final Task task = createTaskStackOnDisplay(mDisplayContent); final int taskId = task.mTaskId; - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity3 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity3 = createActivityRecordInTask(mDisplayContent, task); activity1.setTaskOverlay(true); activity2.setTaskOverlay(true); activity3.setTaskOverlay(true); diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java index 75ed928b08a0..6ed762283524 100644 --- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java @@ -44,7 +44,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testFlow() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity); mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(activity); @@ -56,8 +56,8 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testMultiple() { - final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity1 = createTestActivityRecord(mDisplayContent); + final ActivityRecord activity2 = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity1); mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(activity1); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity2); @@ -72,7 +72,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testClear() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.clear(); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); @@ -80,7 +80,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testRemoveFinishingInvisibleActivityFromUnknown() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); activity.finishing = true; activity.mVisibleRequested = true; @@ -90,7 +90,7 @@ public class UnknownAppVisibilityControllerTest extends WindowTestsBase { @Test public void testAppRemoved() { - final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); + final ActivityRecord activity = createTestActivityRecord(mDisplayContent); mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(activity); mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(activity); assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java index 8ac44f2afcfd..4163a9a546a0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java @@ -810,8 +810,7 @@ public class WindowContainerTests extends WindowTestsBase { public void testOnDisplayChanged() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(mDisplayContent, task); final DisplayContent newDc = createNewDisplay(); stack.getDisplayArea().removeStack(stack); @@ -854,19 +853,17 @@ public class WindowContainerTests extends WindowTestsBase { public void testTaskCanApplyAnimation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(stack, 0 /* userId */); - final ActivityRecord activity2 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); - final ActivityRecord activity1 = - WindowTestUtils.createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, task); + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, task); verifyWindowContainerApplyAnimation(task, activity1, activity2); } @Test public void testStackCanApplyAnimation() { final Task stack = createTaskStackOnDisplay(mDisplayContent); - final ActivityRecord activity2 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + final ActivityRecord activity2 = createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); - final ActivityRecord activity1 = WindowTestUtils.createActivityRecordInTask(mDisplayContent, + final ActivityRecord activity1 = createActivityRecordInTask(mDisplayContent, createTaskInStack(stack, 0 /* userId */)); verifyWindowContainerApplyAnimation(stack, activity1, activity2); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 8cfa4f00c8b6..91352972e772 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -931,8 +931,7 @@ public class WindowOrganizerTests extends WindowTestsBase { final Task stack = createStack(); final Task task = createTask(stack); - final ActivityRecord record = WindowTestUtils.createActivityRecordInTask( - stack.mDisplayContent, task); + final ActivityRecord record = createActivityRecordInTask(stack.mDisplayContent, task); stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); record.setTaskDescription(new ActivityManager.TaskDescription("TestDescription")); @@ -966,8 +965,7 @@ public class WindowOrganizerTests extends WindowTestsBase { public void testInterceptBackPressedOnTaskRoot() throws RemoteException { final Task stack = createStack(); final Task task = createTask(stack); - final ActivityRecord activity = WindowTestUtils.createActivityRecordInTask( - stack.mDisplayContent, task); + final ActivityRecord activity = createActivityRecordInTask(stack.mDisplayContent, task); final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW); // Setup the task to be controlled by the MW mode organizer diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 3894a2eaa461..f095fd42900b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -357,8 +357,7 @@ public class WindowStateTests extends WindowTestsBase { // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an // activity. Both windows have the FLAG_TURNS_SCREEN_ON so both should call wakeup - final WindowToken windowToken = WindowTestUtils.createTestWindowToken(FIRST_SUB_WINDOW, - mDisplayContent); + final WindowToken windowToken = createTestWindowToken(FIRST_SUB_WINDOW, mDisplayContent); final WindowState firstWindow = createWindow(null, TYPE_APPLICATION, windowToken, "firstWindow"); final WindowState secondWindow = createWindow(null, TYPE_APPLICATION, windowToken, diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java deleted file mode 100644 index 0180d87290a1..000000000000 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2017 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.wm; - -import static android.app.AppOpsManager.OP_NONE; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; -import static com.android.server.wm.WindowContainer.POSITION_TOP; - -import android.os.IBinder; -import android.view.IWindow; -import android.view.WindowManager; - -import com.android.server.wm.WindowTestsBase.ActivityBuilder; - -/** - * A collection of static functions that provide access to WindowManager related test functionality. - */ -class WindowTestUtils { - - /** Creates a {@link Task} and adds it to the specified {@link Task}. */ - static Task createTaskInStack(WindowManagerService service, Task stack, int userId) { - final Task task = new WindowTestsBase.TaskBuilder(stack.mStackSupervisor) - .setUserId(userId) - .setStack(stack) - .build(); - return task; - } - - /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */ - static ActivityRecord createActivityRecordInTask(DisplayContent dc, Task task) { - final ActivityRecord activity = createTestActivityRecord(dc); - task.addChild(activity, POSITION_TOP); - return activity; - } - - static ActivityRecord createTestActivityRecord(Task stack) { - final ActivityRecord activity = new ActivityBuilder(stack.mAtmService) - .setStack(stack) - .setCreateTask(true) - .build(); - postCreateActivitySetup(activity, stack.getDisplayContent()); - return activity; - } - - static ActivityRecord createTestActivityRecord(DisplayContent dc) { - final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build(); - postCreateActivitySetup(activity, dc); - return activity; - } - - private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { - activity.onDisplayChanged(dc); - activity.setOccludesParent(true); - activity.setVisible(true); - activity.mVisibleRequested = true; - } - - static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { - return createTestWindowToken(type, dc, false /* persistOnEmpty */); - } - - static TestWindowToken createTestWindowToken(int type, DisplayContent dc, - boolean persistOnEmpty) { - SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock); - - return new TestWindowToken(type, dc, persistOnEmpty); - } - - /* Used so we can gain access to some protected members of the {@link WindowToken} class */ - static class TestWindowToken extends WindowToken { - - private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { - super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, - false /* ownerCanManageAppTokens */); - } - - int getWindowsCount() { - return mChildren.size(); - } - - boolean hasWindow(WindowState w) { - return mChildren.contains(w); - } - } - - /** Used to track resize reports. */ - static class TestWindowState extends WindowState { - boolean mResizeReported; - - TestWindowState(WindowManagerService service, Session session, IWindow window, - WindowManager.LayoutParams attrs, WindowToken token) { - super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, - false /* ownerCanAddInternalSystemWindow */); - } - - @Override - void reportResized() { - super.reportResized(); - mResizeReported = true; - } - - @Override - public boolean isGoneForLayoutLw() { - return false; - } - - @Override - void updateResizingWindowIfNeeded() { - // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive - // the system that it can actually update the window. - boolean hadSurface = mHasSurface; - mHasSurface = true; - - super.updateResizingWindowIfNeeded(); - - mHasSurface = hadSurface; - } - } -} diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index ec19a58b17c4..5ce61b4e4916 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -47,6 +47,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -66,6 +67,7 @@ import android.content.res.Configuration; import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; @@ -239,7 +241,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private WindowToken createWindowToken( DisplayContent dc, int windowingMode, int activityType, int type) { if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { - return WindowTestUtils.createTestWindowToken(type, dc); + return createTestWindowToken(type, dc); } return createActivityRecord(dc, windowingMode, activityType); @@ -249,10 +251,39 @@ class WindowTestsBase extends SystemServiceTestsBase { return createTestActivityRecord(dc, windowingMode, activityType); } - ActivityRecord createTestActivityRecord(DisplayContent dc, int - windowingMode, int activityType) { + ActivityRecord createTestActivityRecord(DisplayContent dc, int windowingMode, + int activityType) { final Task stack = createTaskStackOnDisplay(windowingMode, activityType, dc); - return WindowTestUtils.createTestActivityRecord(stack); + return createTestActivityRecord(stack); + } + + /** Creates an {@link ActivityRecord} and adds it to the specified {@link Task}. */ + static ActivityRecord createActivityRecordInTask(DisplayContent dc, Task task) { + final ActivityRecord activity = createTestActivityRecord(dc); + task.addChild(activity, POSITION_TOP); + return activity; + } + + static ActivityRecord createTestActivityRecord(DisplayContent dc) { + final ActivityRecord activity = new ActivityBuilder(dc.mWmService.mAtmService).build(); + postCreateActivitySetup(activity, dc); + return activity; + } + + static ActivityRecord createTestActivityRecord(Task stack) { + final ActivityRecord activity = new ActivityBuilder(stack.mAtmService) + .setStack(stack) + .setCreateTask(true) + .build(); + postCreateActivitySetup(activity, stack.getDisplayContent()); + return activity; + } + + private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { + activity.onDisplayChanged(dc); + activity.setOccludesParent(true); + activity.setVisible(true); + activity.mVisibleRequested = true; } WindowState createWindow(WindowState parent, int type, String name) { @@ -274,8 +305,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } WindowState createAppWindow(Task task, int type, String name) { - final ActivityRecord activity = - WindowTestUtils.createTestActivityRecord(task.getDisplayContent()); + final ActivityRecord activity = createTestActivityRecord(task.getDisplayContent()); task.addChild(activity, 0); return createWindow(null, type, activity, name); } @@ -390,7 +420,11 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link Task} and adds it to the specified {@link Task}. */ Task createTaskInStack(Task stack, int userId) { - return WindowTestUtils.createTaskInStack(mWm, stack, userId); + final Task task = new TaskBuilder(stack.mStackSupervisor) + .setUserId(userId) + .setStack(stack) + .build(); + return task; } /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ @@ -432,12 +466,11 @@ class WindowTestsBase extends SystemServiceTestsBase { return createNewDisplay(displayInfo, true /* supportIme */); } - /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ - WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs, - WindowToken token) { + /** Creates a {@link TestWindowState} */ + TestWindowState createWindowState(WindowManager.LayoutParams attrs, WindowToken token) { SystemServicesTestRule.checkHoldsLock(mWm.mGlobalLock); - return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token); + return new TestWindowState(mWm, mMockSession, mIWindow, attrs, token); } /** Creates a {@link DisplayContent} as parts of simulate display info for test. */ @@ -1055,4 +1088,66 @@ class WindowTestsBase extends SystemServiceTestsBase { public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { } } + + static TestWindowToken createTestWindowToken(int type, DisplayContent dc) { + return createTestWindowToken(type, dc, false /* persistOnEmpty */); + } + + static TestWindowToken createTestWindowToken(int type, DisplayContent dc, + boolean persistOnEmpty) { + SystemServicesTestRule.checkHoldsLock(dc.mWmService.mGlobalLock); + + return new TestWindowToken(type, dc, persistOnEmpty); + } + + /** Used so we can gain access to some protected members of the {@link WindowToken} class */ + static class TestWindowToken extends WindowToken { + + private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) { + super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc, + false /* ownerCanManageAppTokens */); + } + + int getWindowsCount() { + return mChildren.size(); + } + + boolean hasWindow(WindowState w) { + return mChildren.contains(w); + } + } + + /** Used to track resize reports. */ + static class TestWindowState extends WindowState { + boolean mResizeReported; + + TestWindowState(WindowManagerService service, Session session, IWindow window, + WindowManager.LayoutParams attrs, WindowToken token) { + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, + false /* ownerCanAddInternalSystemWindow */); + } + + @Override + void reportResized() { + super.reportResized(); + mResizeReported = true; + } + + @Override + public boolean isGoneForLayoutLw() { + return false; + } + + @Override + void updateResizingWindowIfNeeded() { + // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive + // the system that it can actually update the window. + boolean hadSurface = mHasSurface; + mHasSurface = true; + + super.updateResizingWindowIfNeeded(); + + mHasSurface = hadSurface; + } + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index f185da395754..d9c48fc4ba37 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -58,8 +58,7 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testAddWindow() { - final WindowTestUtils.TestWindowToken token = - WindowTestUtils.createTestWindowToken(0, mDisplayContent); + final TestWindowToken token = createTestWindowToken(0, mDisplayContent); assertEquals(0, token.getWindowsCount()); @@ -93,7 +92,7 @@ public class WindowTokenTests extends WindowTestsBase { @Test public void testChildRemoval() { final DisplayContent dc = mDisplayContent; - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken(0, dc); + final TestWindowToken token = createTestWindowToken(0, dc); assertEquals(token, dc.getWindowToken(token.token)); @@ -116,7 +115,7 @@ public class WindowTokenTests extends WindowTestsBase { */ @Test public void testTokenRemovalProcess() { - final WindowTestUtils.TestWindowToken token = WindowTestUtils.createTestWindowToken( + final TestWindowToken token = createTestWindowToken( TYPE_TOAST, mDisplayContent, true /* persistOnEmpty */); // Verify that the token is on the display diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index bcb1736f416e..464f318a8bac 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1209,11 +1209,14 @@ public class TelecomManager { /** * Returns a list of all {@link PhoneAccount}s registered for the calling package. * + * @deprecated Use {@link #getSelfManagedPhoneAccounts()} instead to get only self-managed + * {@link PhoneAccountHandle} for the calling package. * @return A list of {@code PhoneAccountHandle} objects. * @hide */ @SystemApi @SuppressLint("Doclava125") + @Deprecated public List<PhoneAccountHandle> getPhoneAccountsForPackage() { try { if (isServiceConnected()) { diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index e233fed7e785..9da17db6a573 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -11,6 +11,7 @@ android_test { "androidx.test.rules", "mockito-target-minus-junit4", "truth-prebuilt", + "platform-test-annotations", ], java_resource_dirs: ["res"], certificate: "platform", diff --git a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 3e9f625ecdd9..3db011683a86 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.server.protolog; +package com.android.internal.protolog; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.server.protolog.ProtoLogImpl.PROTOLOG_VERSION; +import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -42,7 +42,7 @@ import android.util.proto.ProtoInputStream; import androidx.test.filters.SmallTest; -import com.android.server.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.IProtoLogGroup; import org.junit.After; import org.junit.Before; diff --git a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java index 02540559fbd0..ae5021638745 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/ProtoLogViewerConfigReaderTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog; +package com.android.internal.protolog; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; diff --git a/services/tests/servicestests/src/com/android/server/protolog/common/LogDataTypeTest.java b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java index 4c7f5fdc821c..e20ca3df57c7 100644 --- a/services/tests/servicestests/src/com/android/server/protolog/common/LogDataTypeTest.java +++ b/tests/Internal/src/com/android/internal/protolog/common/LogDataTypeTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.protolog.common; +package com.android.internal.protolog.common; import static org.junit.Assert.assertEquals; diff --git a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt index c3d689c5209d..9b15b0445642 100644 --- a/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt +++ b/tests/SilkFX/src/com/android/test/silkfx/common/ColorModeControls.kt @@ -26,10 +26,10 @@ import android.widget.LinearLayout import android.widget.TextView import com.android.test.silkfx.R import com.android.test.silkfx.app.WindowObserver -import java.lang.Exception 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) { @@ -37,14 +37,17 @@ class ColorModeControls : LinearLayout, WindowObserver { } private var window: Window? = null - private var currentMode: TextView? = 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") - currentMode = findViewById(R.id.current_mode)!! + currentModeDisplay = findViewById(R.id.current_mode)!! setColorMode(window.colorMode) findViewById<Button>(R.id.mode_default)!!.setOnClickListener { @@ -63,21 +66,30 @@ class ColorModeControls : LinearLayout, WindowObserver { 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 - currentMode?.run { + 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 150)" - COLOR_MODE_HDR10 -> "HDR10 (sdr white point 150)" + ActivityInfo.COLOR_MODE_HDR -> "HDR (sdr white point $whitePoint)" + COLOR_MODE_HDR10 -> "HDR10 (sdr white point $whitePoint)" else -> "Unknown" } } @@ -101,4 +113,10 @@ class ColorModeControls : LinearLayout, WindowObserver { } } } + + 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/hdr/BlingyNotification.kt b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt index e517c3c62e2a..4ad21faec9d4 100644 --- a/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt +++ b/tests/SilkFX/src/com/android/test/silkfx/hdr/BlingyNotification.kt @@ -71,9 +71,9 @@ class BlingyNotification : BaseDrawingView { paint.shader = LinearGradient(0f, 0f, w.toFloat(), 0f, longArrayOf( color(1f, 1f, 1f, 0f), - color(1f, 1f, 1f, .4f), - color(2f, 2f, 2f, .8f), - color(1f, 1f, 1f, .4f), + 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), diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 5285b04f67d7..55def498a0cd 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -22,7 +22,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; -import com.android.cts.install.lib.host.InstallUtilsHost; +import android.cts.install.lib.host.InstallUtilsHost; + import com.android.ddmlib.Log; import com.android.tests.rollback.host.AbandonSessionsRule; import com.android.tests.util.ModuleTestUtils; 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/tools/protologtool/Android.bp b/tools/protologtool/Android.bp index ce551bd0cc10..0be80d31990a 100644 --- a/tools/protologtool/Android.bp +++ b/tools/protologtool/Android.bp @@ -2,9 +2,9 @@ java_library_host { name: "protologtool-lib", srcs: [ "src/com/android/protolog/tool/**/*.kt", + ":protolog-common-src", ], static_libs: [ - "protolog-common", "javaparser", "platformprotos", "jsonlib", diff --git a/tools/protologtool/src/com/android/protolog/tool/LogParser.kt b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt index a59038fc99a0..645c5672da64 100644 --- a/tools/protologtool/src/com/android/protolog/tool/LogParser.kt +++ b/tools/protologtool/src/com/android/protolog/tool/LogParser.kt @@ -16,16 +16,15 @@ package com.android.protolog.tool +import com.android.internal.protolog.ProtoLogFileProto +import com.android.internal.protolog.ProtoLogMessage +import com.android.internal.protolog.common.InvalidFormatStringException +import com.android.internal.protolog.common.LogDataType import com.android.json.stream.JsonReader -import com.android.server.protolog.common.InvalidFormatStringException -import com.android.server.protolog.common.LogDataType -import com.android.server.protolog.ProtoLogMessage -import com.android.server.protolog.ProtoLogFileProto import java.io.BufferedReader import java.io.InputStream import java.io.InputStreamReader import java.io.PrintStream -import java.lang.Exception import java.text.SimpleDateFormat import java.util.Date import java.util.Locale diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt index 75493b6427cb..42b628b0e262 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogGroupReader.kt @@ -17,7 +17,7 @@ package com.android.protolog.tool import com.android.protolog.tool.Constants.ENUM_VALUES_METHOD -import com.android.server.protolog.common.IProtoLogGroup +import com.android.internal.protolog.common.IProtoLogGroup import java.io.File import java.net.URLClassLoader diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index 36ea41129450..27e61a139451 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -16,7 +16,7 @@ package com.android.protolog.tool -import com.android.server.protolog.common.LogDataType +import com.android.internal.protolog.common.LogDataType import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.NodeList @@ -89,7 +89,7 @@ class SourceTransformer( // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) // Replace call to a stub method with an actual implementation. - // Out: com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, null, arg) + // Out: ProtoLogImpl.e(GROUP, 1234, null, arg) newCall.setScope(protoLogImplClassNode) // Create a call to ProtoLog$Cache.GROUP_enabled // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled @@ -119,9 +119,9 @@ class SourceTransformer( } blockStmt.addStatement(ExpressionStmt(newCall)) // Create an IF-statement with the previously created condition. - // Out: if (com.android.server.protolog.ProtoLogImpl.isEnabled(GROUP)) { + // Out: if (ProtoLogImpl.isEnabled(GROUP)) { // long protoLogParam0 = arg; - // com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); + // ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); // } ifStmt = IfStmt(isLogEnabled, blockStmt, null) } else { diff --git a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt index cf36651c3e39..3cfbb435a764 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt @@ -31,7 +31,7 @@ class CommandOptionsTest { private const val TEST_PROTOLOG_CLASS = "com.android.server.wm.ProtoLog" private const val TEST_PROTOLOGIMPL_CLASS = "com.android.server.wm.ProtoLogImpl" private const val TEST_PROTOLOGCACHE_CLASS = "com.android.server.wm.ProtoLog\$Cache" - private const val TEST_PROTOLOGGROUP_CLASS = "com.android.server.wm.ProtoLogGroup" + private const val TEST_PROTOLOGGROUP_CLASS = "com.android.internal.protolog.ProtoLogGroup" private const val TEST_PROTOLOGGROUP_JAR = "out/soong/.intermediates/frameworks/base/" + "services/core/services.core.wm.protologgroups/android_common/javac/" + "services.core.wm.protologgroups.jar" diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt index dd8a0b1c50b4..0d2b91d6cfb8 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt @@ -33,8 +33,8 @@ class EndToEndTest { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.server.protolog.common.ProtoLog; - import static com.android.server.wm.ProtoLogGroup.GROUP; + import com.android.internal.protolog.common.ProtoLog; + import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { @@ -46,11 +46,11 @@ class EndToEndTest { """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", - "--protolog-class", "com.android.server.protolog.common.ProtoLog", - "--protolog-impl-class", "com.android.server.protolog.ProtoLogImpl", + "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--protolog-impl-class", "com.android.internal.protolog.ProtoLogImpl", "--protolog-cache-class", - "com.android.server.protolog.ProtoLog${"\$\$"}Cache", - "--loggroups-class", "com.android.server.wm.ProtoLogGroup", + "com.android.server.wm.ProtoLogCache", + "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) @@ -64,8 +64,8 @@ class EndToEndTest { val output = run( src = "frameworks/base/org/example/Example.java" to """ package org.example; - import com.android.server.protolog.common.ProtoLog; - import static com.android.server.wm.ProtoLogGroup.GROUP; + import com.android.internal.protolog.common.ProtoLog; + import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { @@ -77,8 +77,8 @@ class EndToEndTest { """.trimIndent(), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", - "--protolog-class", "com.android.server.protolog.common.ProtoLog", - "--loggroups-class", "com.android.server.wm.ProtoLogGroup", + "--protolog-class", "com.android.internal.protolog.common.ProtoLog", + "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-conf", "out.json", "frameworks/base/org/example/Example.java")) diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt index 04a3bfa499d8..67a31da87081 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt @@ -17,8 +17,8 @@ package com.android.protolog.tool import com.android.json.stream.JsonReader -import com.android.server.protolog.ProtoLogMessage -import com.android.server.protolog.ProtoLogFileProto +import com.android.internal.protolog.ProtoLogMessage +import com.android.internal.protolog.ProtoLogFileProto import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test |