diff options
120 files changed, 2957 insertions, 1631 deletions
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java index 2fdba0af2c1b..c121bd9caa57 100644 --- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java +++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java @@ -27,6 +27,7 @@ import android.content.pm.UserInfo; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; +import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -130,6 +131,47 @@ public class UserLifecycleTests { } } + /** Tests switching to an already-created, but no-longer-running, user. */ + @Test + public void switchUser_stopped() throws Exception { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int startUser = mAm.getCurrentUser(); + final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true); + final CountDownLatch latch = new CountDownLatch(1); + registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser); + mRunner.resumeTiming(); + + mAm.switchUser(testUser); + boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + + mRunner.pauseTiming(); + attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success); + switchUser(startUser); + removeUser(testUser); + mRunner.resumeTiming(); + } + } + + /** Tests switching to an already-created already-running non-owner user. */ + @Test + public void switchUser_running() throws Exception { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final int startUser = mAm.getCurrentUser(); + final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false); + mRunner.resumeTiming(); + + switchUser(testUser); + + mRunner.pauseTiming(); + attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser)); + switchUser(startUser); + removeUser(testUser); + mRunner.resumeTiming(); + } + } + @Test public void stopUser() throws Exception { while (mRunner.keepRunning()) { @@ -188,6 +230,34 @@ public class UserLifecycleTests { } } + /** Tests starting an already-created, but no-longer-running, profile. */ + @Test + public void managedProfileUnlock_stopped() throws Exception { + while (mRunner.keepRunning()) { + mRunner.pauseTiming(); + final UserInfo userInfo = mUm.createProfileForUser("TestUser", + UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser()); + // Start the profile initially, then stop it. Similar to setQuietModeEnabled. + final CountDownLatch latch1 = new CountDownLatch(1); + registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, userInfo.id); + mIam.startUserInBackground(userInfo.id); + latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + stopUser(userInfo.id, true); + + // Now we restart the profile. + final CountDownLatch latch2 = new CountDownLatch(1); + registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch2, userInfo.id); + mRunner.resumeTiming(); + + mIam.startUserInBackground(userInfo.id); + latch2.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); + + mRunner.pauseTiming(); + removeUser(userInfo.id); + mRunner.resumeTiming(); + } + } + @Test public void ephemeralUserStopped() throws Exception { while (mRunner.keepRunning()) { @@ -262,6 +332,35 @@ public class UserLifecycleTests { latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS); } + /** + * Creates a user and waits for its ACTION_USER_UNLOCKED. + * Then switches to back to the original user and waits for its switchUser() to finish. + * + * @param stopNewUser whether to stop the new user after switching to otherUser. + * @return userId of the newly created user. + */ + private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception { + final int origUser = mAm.getCurrentUser(); + // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED + final int testUser = mUm.createUser("TestUser", 0).id; + final CountDownLatch latch1 = new CountDownLatch(1); + registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser); + mAm.switchUser(testUser); + attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser, + latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS)); + + // Second, switch back to origUser, waiting merely for switchUser() to finish + switchUser(origUser); + attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser()); + + if (stopNewUser) { + stopUser(testUser, true); + attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser)); + } + + return testUser; + } + private void registerUserSwitchObserver(final CountDownLatch switchLatch, final CountDownLatch bootCompleteLatch, final int userId) throws Exception { ActivityManager.getService().registerUserSwitchObserver( @@ -313,4 +412,14 @@ public class UserLifecycleTests { mUsersToRemove.add(userId); } } + + private void attestTrue(String message, boolean attestion) { + if (!attestion) { + Log.w(TAG, message); + } + } + + private void attestFalse(String message, boolean attestion) { + attestTrue(message, !attestion); + } } diff --git a/api/current.txt b/api/current.txt index d4a155499aa5..cb53ba11a4cd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -45108,6 +45108,7 @@ package android.telephony { method public boolean canChangeDtmfToneLength(); method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); + method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot(); method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); method public int getCardIdForDefaultEuicc(); diff --git a/api/system-current.txt b/api/system-current.txt index d1018be2532d..3f74596999cb 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8063,7 +8063,6 @@ package android.telephony { method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); diff --git a/api/test-current.txt b/api/test-current.txt index 1e24ff953b2a..67a26f39ebbc 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -716,6 +716,11 @@ package android.content.pm { package android.content.res { + public final class AssetManager implements java.lang.AutoCloseable { + method @NonNull public String[] getApkPaths(); + method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOverlayableMap(String); + } + public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable { field public int assetsSeq; field public final android.app.WindowConfiguration windowConfiguration; diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 6d5fe7b3446a..49470b4f4e95 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -269,12 +269,10 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& strea std::string ConcatPolicies(const std::vector<std::string>& policies) { std::string message; for (const std::string& policy : policies) { - if (message.empty()) { - message.append(policy); - } else { - message.append(policy); + if (!message.empty()) { message.append("|"); } + message.append(policy); } return message; diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 5328dda03893..deb181f4fd0a 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -687,6 +687,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29; + /** + * Value for {@link #privateFlags}: whether this app is pre-installed on the + * ODM partition of the system image. + * @hide + */ + public static final int PRIVATE_FLAG_ODM = 1 << 30; + /** @hide */ @IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = { PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE, @@ -717,6 +724,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE, PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, + PRIVATE_FLAG_ODM, }) @Retention(RetentionPolicy.SOURCE) public @interface ApplicationInfoPrivateFlags {} @@ -1093,6 +1101,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public String appComponentFactory; /** + * Resource id of {@link com.android.internal.R.styleable.AndroidManifestProvider_icon} + * @hide + */ + public int iconRes; + + /** + * Resource id of {@link com.android.internal.R.styleable.AndroidManifestProvider_roundIcon} + * @hide + */ + public int roundIconRes; + + /** * The category of this app. Categories are used to cluster multiple apps * together into meaningful groups, such as when summarizing battery, * network, or disk usage. Apps should only define this value when they fit @@ -1571,6 +1591,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { classLoaderName = orig.classLoaderName; splitClassLoaderNames = orig.splitClassLoaderNames; appComponentFactory = orig.appComponentFactory; + iconRes = orig.iconRes; + roundIconRes = orig.roundIconRes; compileSdkVersion = orig.compileSdkVersion; compileSdkVersionCodename = orig.compileSdkVersionCodename; mHiddenApiPolicy = orig.mHiddenApiPolicy; @@ -1650,6 +1672,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(compileSdkVersion); dest.writeString(compileSdkVersionCodename); dest.writeString(appComponentFactory); + dest.writeInt(iconRes); + dest.writeInt(roundIconRes); dest.writeInt(mHiddenApiPolicy); dest.writeInt(hiddenUntilInstalled ? 1 : 0); dest.writeString(zygotePreloadName); @@ -1724,6 +1748,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { compileSdkVersion = source.readInt(); compileSdkVersionCodename = source.readString(); appComponentFactory = source.readString(); + iconRes = source.readInt(); + roundIconRes = source.readInt(); mHiddenApiPolicy = source.readInt(); hiddenUntilInstalled = source.readInt() != 0; zygotePreloadName = source.readString(); @@ -1970,6 +1996,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } /** @hide */ + public boolean isOdm() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + + /** @hide */ public boolean isPartiallyDirectBootAware() { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0; } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 93bc6d7eb583..8981000714dd 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -49,6 +49,8 @@ import android.annotation.StringRes; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.app.ActivityTaskManager; +import android.app.ActivityThread; +import android.app.ResourcesManager; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; @@ -69,6 +71,7 @@ import android.os.FileUtils; import android.os.Parcel; import android.os.Parcelable; import android.os.PatternMatcher; +import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; @@ -92,6 +95,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.util.apk.ApkSignatureVerifier; +import android.view.Display; import android.view.Gravity; import com.android.internal.R; @@ -320,6 +324,8 @@ public class PackageParser { private int mParseError = PackageManager.INSTALL_SUCCEEDED; private static boolean sCompatibilityModeEnabled = true; + private static boolean sUseRoundIcon = false; + private static final int PARSE_DEFAULT_INSTALL_LOCATION = PackageInfo.INSTALL_LOCATION_UNSPECIFIED; private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1; @@ -3437,6 +3443,11 @@ public class PackageParser { TypedArray sa = res.obtainAttributes(parser, com.android.internal.R.styleable.AndroidManifestApplication); + ai.iconRes = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); + ai.roundIconRes = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 0); + if (!parsePackageItemInfo(owner, ai, outError, "<application>", sa, false /*nameRequired*/, com.android.internal.R.styleable.AndroidManifestApplication_name, @@ -4240,9 +4251,7 @@ public class PackageParser { } } - final boolean useRoundIcon = - Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); - int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; + int roundIconVal = sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0; if (roundIconVal != 0) { outInfo.icon = roundIconVal; outInfo.nonLocalizedLabel = null; @@ -5750,9 +5759,7 @@ public class PackageParser { outInfo.nonLocalizedLabel = v.coerceToString(); } - final boolean useRoundIcon = - Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon); - int roundIconVal = useRoundIcon ? sa.getResourceId( + int roundIconVal = sUseRoundIcon ? sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0; if (roundIconVal != 0) { outInfo.icon = roundIconVal; @@ -6920,6 +6927,11 @@ public class PackageParser { } /** @hide */ + public boolean isOdm() { + return applicationInfo.isOdm(); + } + + /** @hide */ public boolean isPrivileged() { return applicationInfo.isPrivilegedApp(); } @@ -7739,6 +7751,7 @@ public class PackageParser { } ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state); ai.resourceDirs = state.overlayPaths; + ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes; } @UnsupportedAppUsage @@ -8344,6 +8357,39 @@ public class PackageParser { sCompatibilityModeEnabled = compatibilityModeEnabled; } + /** + * @hide + */ + public static void readConfigUseRoundIcon(Resources r) { + if (r != null) { + sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon); + return; + } + + ApplicationInfo androidAppInfo; + try { + androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo( + "android", 0 /* flags */, + UserHandle.myUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + Resources systemResources = Resources.getSystem(); + + // Create in-flight as this overlayable resource is only used when config changes + Resources overlayableRes = ResourcesManager.getInstance().getResources(null, + null, + null, + androidAppInfo.resourceDirs, + androidAppInfo.sharedLibraryFiles, + Display.DEFAULT_DISPLAY, + null, + systemResources.getCompatibilityInfo(), + systemResources.getClassLoader()); + + sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon); + } + public static class PackageParserException extends Exception { public final int error; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 514015fe0c86..e5ef67b7d4bd 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; import android.annotation.StyleRes; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.Configuration.NativeConfig; @@ -357,6 +358,22 @@ public final class AssetManager implements AutoCloseable { return sEmptyApkAssets; } + /** @hide */ + @TestApi + public @NonNull String[] getApkPaths() { + synchronized (this) { + if (mOpen) { + String[] paths = new String[mApkAssets.length]; + final int count = mApkAssets.length; + for (int i = 0; i < count; i++) { + paths[i] = mApkAssets[i].getAssetPath(); + } + return paths; + } + } + return new String[0]; + } + /** * Returns a cookie for use with the other APIs of AssetManager. * @return 0 if the path was not found, otherwise a positive integer cookie representing @@ -1356,6 +1373,7 @@ public final class AssetManager implements AutoCloseable { /** * @hide */ + @TestApi @GuardedBy("this") public @Nullable Map<String, String> getOverlayableMap(String packageName) { synchronized (this) { diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 5d33b49e181b..336c2e51c4a3 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -38,7 +38,8 @@ public class FeatureFlagUtils { public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; public static final String SAFETY_HUB = "settings_safety_hub"; public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press"; - public static final String GLOBAL_ACTIONS_GRID_ENABLED = "settings_global_actions_grid_enabled"; + public static final String FORCE_GLOBAL_ACTIONS_GRID_ENABLED = + "settings_global_actions_force_grid_enabled"; public static final String GLOBAL_ACTIONS_PANEL_ENABLED = "settings_global_actions_panel_enabled"; public static final String DYNAMIC_SYSTEM = "settings_dynamic_system"; @@ -58,7 +59,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); DEFAULT_FLAGS.put(SAFETY_HUB, "true"); DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); - DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true"); + DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false"); DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true"); DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true"); DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false"); diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index 35cf129d81b8..f9b629c85fb0 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -566,7 +566,7 @@ public abstract class LayoutInflater { String layout = res.getResourceEntryName(resource); try { - Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView"); + Class clazz = Class.forName("" + pkg + ".CompiledView", false, mPrecompiledClassLoader); Method inflater = clazz.getMethod(layout, Context.class, int.class); View view = (View) inflater.invoke(null, mContext, resource); @@ -827,8 +827,8 @@ public abstract class LayoutInflater { if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it - clazz = mContext.getClassLoader().loadClass( - prefix != null ? (prefix + name) : name).asSubclass(View.class); + clazz = Class.forName(prefix != null ? (prefix + name) : name, false, + mContext.getClassLoader()).asSubclass(View.class); if (mFilter != null && clazz != null) { boolean allowed = mFilter.onLoadClass(clazz); @@ -846,8 +846,8 @@ public abstract class LayoutInflater { Boolean allowedState = mFilterMap.get(name); if (allowedState == null) { // New class -- remember whether it is allowed - clazz = mContext.getClassLoader().loadClass( - prefix != null ? (prefix + name) : name).asSubclass(View.class); + clazz = Class.forName(prefix != null ? (prefix + name) : name, false, + mContext.getClassLoader()).asSubclass(View.class); boolean allowed = clazz != null && mFilter.onLoadClass(clazz); mFilterMap.put(name, allowed); diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java index 7ab9534941c7..04ac92292740 100644 --- a/core/java/android/view/RenderNodeAnimator.java +++ b/core/java/android/view/RenderNodeAnimator.java @@ -26,6 +26,7 @@ import android.graphics.RecordingCanvas; import android.graphics.RenderNode; import android.os.Build; import android.os.Handler; +import android.os.Looper; import android.util.SparseIntArray; import com.android.internal.util.VirtualRefBasePtr; @@ -191,6 +192,9 @@ public class RenderNodeAnimator extends Animator { } mState = STATE_DELAYED; + if (mHandler == null) { + mHandler = new Handler(true); + } applyInterpolator(); if (mNativePtr == null) { @@ -224,9 +228,6 @@ public class RenderNodeAnimator extends Animator { private void moveToRunningState() { mState = STATE_RUNNING; if (mNativePtr != null) { - if (mHandler == null) { - mHandler = new Handler(); - } nStart(mNativePtr.get()); } notifyStartListeners(); @@ -503,7 +504,11 @@ public class RenderNodeAnimator extends Animator { // Called by native @UnsupportedAppUsage private static void callOnFinished(RenderNodeAnimator animator) { - animator.mHandler.post(animator::onFinished); + if (animator.mHandler != null) { + animator.mHandler.post(animator::onFinished); + } else { + new Handler(Looper.getMainLooper(), null, true).post(animator::onFinished); + } } @Override diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 1c901823566a..72dbbf3b8b87 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -26,8 +26,9 @@ import com.android.internal.app.IAppOpsActiveCallback; import com.android.internal.app.IAppOpsNotedCallback; interface IAppOpsService { - // These first methods are also called by native code, so must + // These methods are also called by native code, so must // be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h + // and not be reordered int checkOperation(int code, int uid, String packageName); int noteOperation(int code, int uid, String packageName); int startOperation(IBinder token, int code, int uid, String packageName, @@ -38,6 +39,10 @@ interface IAppOpsService { void stopWatchingMode(IAppOpsCallback callback); IBinder getToken(IBinder clientToken); int permissionToOpCode(String permission); + int checkAudioOperation(int code, int usage, int uid, String packageName); + // End of methods also called by native code. + // Any new method exposed to native must be added after the last one, do not reorder + int noteProxyOperation(int code, int proxyUid, String proxyPackageName, int callingUid, String callingPackageName); @@ -62,7 +67,6 @@ interface IAppOpsService { void setMode(int code, int uid, String packageName, int mode); @UnsupportedAppUsage void resetAllModes(int reqUserId, String reqPackageName); - int checkAudioOperation(int code, int usage, int uid, String packageName); void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages); void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 8ca0bd1df1eb..afdeb1b602d7 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -197,9 +197,6 @@ public final class Zygote { private Zygote() {} - /** Called for some security initialization before any fork. */ - static native void nativeSecurityInit(); - /** * Forks a new VM instance. The current VM must have been started * with the -Xzygote flag. <b>NOTE: new instance keeps all @@ -384,22 +381,19 @@ public final class Zygote { native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax); /** - * Zygote unmount storage space on initializing. - * This method is called once. - */ - protected static native void nativeUnmountStorageOnInit(); - - /** - * Get socket file descriptors (opened by init) from the environment and - * store them for access from native code later. + * Initialize the native state of the Zygote. This inclues + * - Fetching socket FDs from the environment + * - Initializing security properties + * - Unmounting storage as appropriate + * - Loading necessary performance profile information * * @param isPrimary True if this is the zygote process, false if it is zygote_secondary */ - public static void getSocketFDs(boolean isPrimary) { - nativeGetSocketFDs(isPrimary); + static void initNativeState(boolean isPrimary) { + nativeInitNativeState(isPrimary); } - protected static native void nativeGetSocketFDs(boolean isPrimary); + protected static native void nativeInitNativeState(boolean isPrimary); /** * Returns the raw string value of a system property. diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index 7cca7b77b45d..bb7b09ab4df3 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -20,10 +20,10 @@ import static android.system.OsConstants.S_IRWXG; import static android.system.OsConstants.S_IRWXO; import android.annotation.UnsupportedAppUsage; -import android.content.res.Resources; -import android.content.res.TypedArray; import android.app.ApplicationLoaders; import android.content.pm.SharedLibraryInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; import android.os.Build; import android.os.Environment; import android.os.IInstalld; @@ -863,8 +863,6 @@ public class ZygoteInit { throw new RuntimeException("No ABI list supplied."); } - Zygote.getSocketFDs(isPrimaryZygote); - // In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. if (!enableLazyPreload) { @@ -889,10 +887,8 @@ public class ZygoteInit { // Zygote. Trace.setTracingEnabled(false, 0); - Zygote.nativeSecurityInit(); - // Zygote process unmounts root storage spaces. - Zygote.nativeUnmountStorageOnInit(); + Zygote.initNativeState(isPrimaryZygote); ZygoteHooks.stopZygoteNoThreadCreation(); diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index bf56ef438a1d..d3f9196ce763 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -163,7 +163,7 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { } // Generic idmap parameters - const char* argv[8]; + const char* argv[9]; int argc = 0; struct stat st; @@ -199,6 +199,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) { argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR; } + if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { + argv[argc++] = AssetManager::ODM_OVERLAY_DIR; + } + // Finally, invoke idmap (if any overlay directory exists) if (argc > 5) { execv(AssetManager::IDMAP_BIN, (char* const*)argv); @@ -233,6 +237,10 @@ static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR); } + if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) { + input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR); + } + if (input_dirs.empty()) { LOG(WARNING) << "no directories for idmap2 to scan"; return env->NewObjectArray(0, g_stringClass, nullptr); diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 8dd7e8ea3b90..430b9c505223 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -126,7 +126,7 @@ static constexpr const char* kZygoteInitClassName = "com/android/internal/os/Zyg static jclass gZygoteInitClass; static jmethodID gCreateSystemServerClassLoader; -static bool g_is_security_enforced = true; +static bool gIsSecurityEnforced = true; /** * The maximum number of characters (not including a null terminator) that a @@ -510,7 +510,7 @@ static void PreApplicationInit() { } static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) { - if (!g_is_security_enforced) { + if (!gIsSecurityEnforced) { ALOGI("seccomp disabled by setenforce 0"); return; } @@ -1626,18 +1626,48 @@ std::vector<int> MakeUsapPipeReadFDVector() { return fd_vec; } -} // anonymous namespace +static void UnmountStorageOnInit(JNIEnv* env) { + // Zygote process unmount root storage space initially before every child processes are forked. + // Every forked child processes (include SystemServer) only mount their own root storage space + // and no need unmount storage operation in MountEmulatedStorage method. + // Zygote process does not utilize root storage spaces and unshares its mount namespace below. -namespace android { + // See storage config details at http://source.android.com/tech/storage/ + // Create private mount namespace shared by all children + if (unshare(CLONE_NEWNS) == -1) { + RuntimeAbort(env, __LINE__, "Failed to unshare()"); + return; + } -static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) { - // security_getenforce is not allowed on app process. Initialize and cache - // the value before zygote forks. - g_is_security_enforced = security_getenforce(); + // Mark rootfs as being a slave so that changes from default + // namespace only flow into our children. + if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) { + RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE"); + return; + } - selinux_android_seapp_context_init(); + // Create a staging tmpfs that is shared by our children; they will + // bind mount storage into their respective private namespaces, which + // are isolated from each other. + const char* target_base = getenv("EMULATED_STORAGE_TARGET"); + if (target_base != nullptr) { +#define STRINGIFY_UID(x) __STRING(x) + if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV, + "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) { + ALOGE("Failed to mount tmpfs to %s", target_base); + RuntimeAbort(env, __LINE__, "Failed to mount tmpfs"); + return; + } +#undef STRINGIFY_UID + } + + UnmountTree("/storage"); } +} // anonymous namespace + +namespace android { + static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) { PreApplicationInit(); } @@ -1791,47 +1821,9 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork( FileDescriptorWhitelist::Get()->Allow(path_cstr); } -static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) { - // Zygote process unmount root storage space initially before every child processes are forked. - // Every forked child processes (include SystemServer) only mount their own root storage space - // and no need unmount storage operation in MountEmulatedStorage method. - // Zygote process does not utilize root storage spaces and unshares its mount namespace below. - - // See storage config details at http://source.android.com/tech/storage/ - // Create private mount namespace shared by all children - if (unshare(CLONE_NEWNS) == -1) { - RuntimeAbort(env, __LINE__, "Failed to unshare()"); - return; - } - - // Mark rootfs as being a slave so that changes from default - // namespace only flow into our children. - if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) { - RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE"); - return; - } - - // Create a staging tmpfs that is shared by our children; they will - // bind mount storage into their respective private namespaces, which - // are isolated from each other. - const char* target_base = getenv("EMULATED_STORAGE_TARGET"); - if (target_base != nullptr) { -#define STRINGIFY_UID(x) __STRING(x) - if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV, - "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) { - ALOGE("Failed to mount tmpfs to %s", target_base); - RuntimeAbort(env, __LINE__, "Failed to mount tmpfs"); - return; - } -#undef STRINGIFY_UID - } - - UnmountTree("/storage"); -} - static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter( JNIEnv* env, jclass, jint uidGidMin, jint uidGidMax) { - if (!g_is_security_enforced) { + if (!gIsSecurityEnforced) { ALOGI("seccomp disabled by setenforce 0"); return; } @@ -1883,8 +1875,12 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( * @param is_primary If this process is the primary or secondary Zygote; used to compute the name * of the environment variable storing the file descriptors. */ -static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclass, - jboolean is_primary) { +static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass, + jboolean is_primary) { + /* + * Obtain file descriptors created by init from the environment. + */ + std::string android_socket_prefix(ANDROID_SOCKET_PREFIX); std::string env_var_name = android_socket_prefix + (is_primary ? "zygote" : "zygote_secondary"); char* env_var_val = getenv(env_var_name.c_str()); @@ -1905,6 +1901,30 @@ static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclas } else { ALOGE("Unable to fetch USAP pool socket file descriptor"); } + + /* + * Security Initialization + */ + + // security_getenforce is not allowed on app process. Initialize and cache + // the value before zygote forks. + gIsSecurityEnforced = security_getenforce(); + + selinux_android_seapp_context_init(); + + /* + * Storage Initialization + */ + + UnmountStorageOnInit(env); + + /* + * Performance Initialization + */ + + if (!SetTaskProfiles(0, {})) { + ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed"); + } } /** @@ -2001,8 +2021,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv* } static const JNINativeMethod gMethods[] = { - { "nativeSecurityInit", "()V", - (void *) com_android_internal_os_Zygote_nativeSecurityInit }, { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I", (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize }, @@ -2010,8 +2028,6 @@ static const JNINativeMethod gMethods[] = { (void *) com_android_internal_os_Zygote_nativeForkSystemServer }, { "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V", (void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork }, - { "nativeUnmountStorageOnInit", "()V", - (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }, { "nativePreApplicationInit", "()V", (void *) com_android_internal_os_Zygote_nativePreApplicationInit }, { "nativeInstallSeccompUidGidFilter", "(II)V", @@ -2021,8 +2037,8 @@ static const JNINativeMethod gMethods[] = { { "nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V", (void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess }, - { "nativeGetSocketFDs", "(Z)V", - (void *) com_android_internal_os_Zygote_nativeGetSocketFDs }, + { "nativeInitNativeState", "(Z)V", + (void *) com_android_internal_os_Zygote_nativeInitNativeState }, { "nativeGetUsapPipeFDs", "()[I", (void *) com_android_internal_os_Zygote_nativeGetUsapPipeFDs }, { "nativeRemoveUsapTableEntry", "(I)Z", diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index d8d46560876d..099635246f05 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -102,6 +102,8 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { static const char* kProductOverlayDir = "/product/overlay"; static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/"; static const char* kProductServicesOverlayDir = "/product_services/overlay"; + static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; + static const char* kOdmOverlayDir = "/odm/overlay"; static const char* kApkSuffix = ".apk"; if ((android::base::StartsWith(path, kOverlayDir) @@ -110,7 +112,9 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { || android::base::StartsWith(path, kSystemProductOverlayDir) || android::base::StartsWith(path, kProductOverlayDir) || android::base::StartsWith(path, kSystemProductServicesOverlayDir) - || android::base::StartsWith(path, kProductServicesOverlayDir)) + || android::base::StartsWith(path, kProductServicesOverlayDir) + || android::base::StartsWith(path, kSystemOdmOverlayDir) + || android::base::StartsWith(path, kOdmOverlayDir)) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; diff --git a/core/tests/featureflagtests/Android.bp b/core/tests/featureflagtests/Android.bp new file mode 100644 index 000000000000..8730b7012c4a --- /dev/null +++ b/core/tests/featureflagtests/Android.bp @@ -0,0 +1,19 @@ +android_test { + name: "FrameworksCoreFeatureFlagTests", + // We only want this apk build for tests. + // Include all test java files. + srcs: ["src/**/*.java"], + dxflags: ["--core-library"], + static_libs: [ + "android-common", + "frameworks-core-util-lib", + "androidx.test.rules", + ], + libs: [ + "android.test.runner", + "android.test.base", + ], + platform_apis: true, + certificate: "platform", + test_suites: ["device-tests"], +} diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk deleted file mode 100644 index ce7cb181b53a..000000000000 --- a/core/tests/featureflagtests/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests - -# Include all test java files. -LOCAL_SRC_FILES := \ - $(call all-java-files-under, src) - -LOCAL_DX_FLAGS := --core-library -LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib androidx.test.rules -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base -LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests -LOCAL_PRIVATE_PLATFORM_APIS := true - -LOCAL_CERTIFICATE := platform -LOCAL_COMPATIBILITY_SUITE := device-tests - -include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk index 97a3d0078e26..fa15241b9cc5 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk @@ -19,7 +19,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_CERTIFICATE := platform LOCAL_USE_AAPT2 := true LOCAL_AAPT_FLAGS := --no-resource-removal include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml index 8ac6953b44e5..7d2840886683 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml @@ -19,5 +19,5 @@ android:versionCode="1" android:versionName="1.0"> <application android:hasCode="false" /> - <overlay android:targetPackage="com.android.overlaytest" android:priority="1" /> + <overlay android:targetPackage="com.android.overlaytest" /> </manifest> diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk index a3470255997d..ada9b3cb625d 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk @@ -19,7 +19,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_CERTIFICATE := platform LOCAL_USE_AAPT2 := true LOCAL_AAPT_FLAGS := --no-resource-removal include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml index f3c39ccbb301..6e75a350204d 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml @@ -19,5 +19,5 @@ android:versionCode="1" android:versionName="1.0"> <application android:hasCode="false" /> - <overlay android:targetPackage="com.android.overlaytest" android:priority="2" /> + <overlay android:targetPackage="com.android.overlaytest" /> </manifest> diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk index b48a46bbda9a..e7348d52adfe 100644 --- a/core/tests/overlaytests/host/Android.mk +++ b/core/tests/overlaytests/host/Android.mk @@ -21,7 +21,7 @@ LOCAL_MODULE := OverlayHostTests LOCAL_JAVA_LIBRARIES := tradefed LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_TARGET_REQUIRED_MODULES := \ - OverlayHostTests_BadSignatureOverlay \ + OverlayHostTests_NonPlatformSignatureOverlay \ OverlayHostTests_PlatformSignatureStaticOverlay \ OverlayHostTests_PlatformSignatureOverlay \ OverlayHostTests_UpdateOverlay \ diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index c133469bbf80..99b6421d2bc7 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -67,10 +67,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { } @Test - public void failToInstallNonPlatformSignedOverlay() throws Exception { + public void failToInstallNonPlatformSignedOverlayTargetPreQ() throws Exception { try { - installPackage("OverlayHostTests_BadSignatureOverlay.apk"); - fail("installed a non-platform signed overlay"); + installPackage("OverlayHostTests_NonPlatformSignatureOverlay.apk"); + fail("installed a non-platform signed overlay with targetSdkVersion < Q"); } catch (Exception e) { // Expected. } @@ -165,7 +165,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { private void delay() { try { - Thread.sleep(100); + Thread.sleep(1000); } catch (InterruptedException e) { } } diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk index 3d2410dd77a5..cc7704b0ce98 100644 --- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk @@ -18,7 +18,7 @@ my_package_prefix := com.android.server.om.hosttest.signature_overlay include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_PACKAGE_NAME := OverlayHostTests_BadSignatureOverlay +LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml index 26b3875caab6..67592f834bb2 100644 --- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml +++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml @@ -16,6 +16,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.server.om.hosttest.signature_overlay"> + <uses-sdk android:targetSdkVersion="28" /> <application android:hasCode="false" /> <overlay android:targetPackage="android" /> </manifest> diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk index c7b2dd1ac8f9..f8607f44bda6 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk @@ -58,7 +58,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1 LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests -LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res @@ -70,7 +69,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2 LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests -LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml index f1a39817af86..b6ff0c3c6725 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml @@ -17,6 +17,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.server.om.hosttest.app_overlay"> <application android:hasCode="false" /> - <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" - android:category="android.theme" /> + <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" /> </manifest> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 626bbf0001dd..072beae8baf7 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -100,36 +100,6 @@ <font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font> </family> - <family name="arbutus-slab"> - <font weight="400" style="normal">ArbutusSlab-Regular.ttf</font> - </family> - - <family name="arvo"> - <font weight="400" style="normal">Arvo-Regular.ttf</font> - <font weight="400" style="italic">Arvo-Italic.ttf</font> - <font weight="700" style="normal">Arvo-Bold.ttf</font> - <font weight="700" style="italic">Arvo-BoldItalic.ttf</font> - </family> - <alias name="arvo-bold" to="arvo" weight="700" /> - - <family name="lato"> - <font weight="400" style="normal">Lato-Regular.ttf</font> - <font weight="400" style="italic">Lato-Italic.ttf</font> - <font weight="700" style="normal">Lato-Bold.ttf</font> - <font weight="700" style="italic">Lato-BoldItalic.ttf</font> - </family> - <alias name="lato-bold" to="lato" weight="700" /> - - <family name="rubik"> - <font weight="400" style="normal">Rubik-Regular.ttf</font> - <font weight="400" style="italic">Rubik-Italic.ttf</font> - <font weight="500" style="normal">Rubik-Medium.ttf</font> - <font weight="500" style="italic">Rubik-MediumItalic.ttf</font> - <font weight="700" style="normal">Rubik-Bold.ttf</font> - <font weight="700" style="italic">Rubik-BoldItalic.ttf</font> - </family> - <alias name="rubik-medium" to="rubik" weight="500" /> - <family name="source-sans-pro"> <font weight="400" style="normal">SourceSansPro-Regular.ttf</font> <font weight="400" style="italic">SourceSansPro-Italic.ttf</font> diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 365be10f597f..21609d30e92c 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -75,6 +75,7 @@ const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay"; const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay"; const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; +const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay"; const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme"; const char* AssetManager::TARGET_PACKAGE_NAME = "android"; const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h index e22e2d239a55..a015eabc200c 100644 --- a/libs/androidfw/include/androidfw/AssetManager.h +++ b/libs/androidfw/include/androidfw/AssetManager.h @@ -62,6 +62,7 @@ public: static const char* VENDOR_OVERLAY_DIR; static const char* PRODUCT_OVERLAY_DIR; static const char* PRODUCT_SERVICES_OVERLAY_DIR; + static const char* ODM_OVERLAY_DIR; /* * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay * APKs in VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index a3eee0a67d56..55f1911119f4 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -388,9 +388,10 @@ public final class AudioAttributes implements Parcelable { */ public static final int FLAG_NO_SYSTEM_CAPTURE = 0x1 << 12; - private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO | - FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY | - FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_MUTE_HAPTIC; + private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO + | FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY + | FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION + | FLAG_MUTE_HAPTIC | FLAG_NO_SYSTEM_CAPTURE; private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY; diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java index 5d12c3cd251d..b2ebfa934178 100644 --- a/media/java/android/media/AudioPlaybackConfiguration.java +++ b/media/java/android/media/AudioPlaybackConfiguration.java @@ -43,8 +43,6 @@ public final class AudioPlaybackConfiguration implements Parcelable { /** @hide */ public static final int PLAYER_PIID_INVALID = -1; /** @hide */ - public static final int PLAYER_PIID_UNASSIGNED = 0; - /** @hide */ public static final int PLAYER_UPID_INVALID = -1; // information about the implementation diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 50caf733da9d..ee8f1b3eec77 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -50,6 +50,10 @@ public abstract class PlayerBase { private static final boolean DEBUG = DEBUG_APP_OPS || false; private static IAudioService sService; //lazy initialization, use getService() + /** if true, only use OP_PLAY_AUDIO monitoring for logging, and rely on muting to happen + * in AudioFlinger */ + private static final boolean USE_AUDIOFLINGER_MUTING_FOR_OP = true; + // parameters of the player that affect AppOps protected AudioAttributes mAttributes; @@ -67,13 +71,13 @@ public abstract class PlayerBase { // for AppOps private @Nullable IAppOpsService mAppOps; - private IAppOpsCallback mAppOpsCallback; + private @Nullable IAppOpsCallback mAppOpsCallback; @GuardedBy("mLock") private boolean mHasAppOpsPlayAudio = true; private final int mImplType; // uniquely identifies the Player Interface throughout the system (P I Id) - private int mPlayerIId = AudioPlaybackConfiguration.PLAYER_PIID_UNASSIGNED; + private int mPlayerIId = AudioPlaybackConfiguration.PLAYER_PIID_INVALID; @GuardedBy("mLock") private int mState; @@ -104,27 +108,27 @@ public abstract class PlayerBase { * Call from derived class when instantiation / initialization is successful */ protected void baseRegisterPlayer() { - int newPiid = AudioPlaybackConfiguration.PLAYER_PIID_INVALID; - IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); - mAppOps = IAppOpsService.Stub.asInterface(b); - // initialize mHasAppOpsPlayAudio - updateAppOpsPlayAudio(); - // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed - mAppOpsCallback = new IAppOpsCallbackWrapper(this); - try { - mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, - ActivityThread.currentPackageName(), mAppOpsCallback); - } catch (RemoteException e) { - Log.e(TAG, "Error registering appOps callback", e); - mHasAppOpsPlayAudio = false; + if (!USE_AUDIOFLINGER_MUTING_FOR_OP) { + IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); + mAppOps = IAppOpsService.Stub.asInterface(b); + // initialize mHasAppOpsPlayAudio + updateAppOpsPlayAudio(); + // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed + mAppOpsCallback = new IAppOpsCallbackWrapper(this); + try { + mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO, + ActivityThread.currentPackageName(), mAppOpsCallback); + } catch (RemoteException e) { + Log.e(TAG, "Error registering appOps callback", e); + mHasAppOpsPlayAudio = false; + } } try { - newPiid = getService().trackPlayer( + mPlayerIId = getService().trackPlayer( new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this))); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, player will not be tracked", e); } - mPlayerIId = newPiid; } /** @@ -284,6 +288,9 @@ public abstract class PlayerBase { * Must be called synchronized on mLock. */ void updateAppOpsPlayAudio_sync(boolean attributesChanged) { + if (USE_AUDIOFLINGER_MUTING_FOR_OP) { + return; + } boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio; try { int mode = AppOpsManager.MODE_IGNORED; @@ -333,6 +340,9 @@ public abstract class PlayerBase { * @return */ boolean isRestricted_sync() { + if (USE_AUDIOFLINGER_MUTING_FOR_OP) { + return false; + } // check app ops if (mHasAppOpsPlayAudio) { return false; diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 1f2480ba0b47..177f2b8ee491 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -248,16 +248,21 @@ LIBANDROID { ASystemFontIterator_open; # introduced=29 ASystemFontIterator_close; # introduced=29 ASystemFontIterator_next; # introduced=29 - ASystemFont_close; # introduced=29 - ASystemFont_getFontFilePath; # introduced=29 - ASystemFont_getWeight; # introduced=29 - ASystemFont_isItalic; # introduced=29 - ASystemFont_getLocale; # introduced=29 - ASystemFont_getCollectionIndex; # introduced=29 - ASystemFont_getAxisCount; # introduced=29 - ASystemFont_getAxisTag; # introduced=29 - ASystemFont_getAxisValue; # introduced=29 - ASystemFont_matchFamilyStyleCharacter; # introduced=29 + AFont_close; # introduced=29 + AFont_getFontFilePath; # introduced=29 + AFont_getWeight; # introduced=29 + AFont_isItalic; # introduced=29 + AFont_getLocale; # introduced=29 + AFont_getCollectionIndex; # introduced=29 + AFont_getAxisCount; # introduced=29 + AFont_getAxisTag; # introduced=29 + AFont_getAxisValue; # introduced=29 + AFontMatcher_create; # introduced=29 + AFontMatcher_destroy; # introduced=29 + AFontMatcher_setStyle; # introduced=29 + AFontMatcher_setLocales; # introduced=29 + AFontMatcher_setFamilyVariant; # introduced=29 + AFontMatcher_match; # introduced=29 ATrace_beginSection; # introduced=23 ATrace_endSection; # introduced=23 ATrace_isEnabled; # introduced=23 diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp index 4d3d1d66ffda..302cbd11da4b 100644 --- a/native/android/system_fonts.cpp +++ b/native/android/system_fonts.cpp @@ -16,6 +16,8 @@ #include <jni.h> +#include <android/font.h> +#include <android/font_matcher.h> #include <android/system_fonts.h> #include <memory> @@ -53,7 +55,7 @@ struct ASystemFontIterator { XmlDocUniquePtr mCustomizationXmlDoc; }; -struct ASystemFont { +struct AFont { std::string mFilePath; std::unique_ptr<std::string> mLocale; uint16_t mWeight; @@ -62,6 +64,19 @@ struct ASystemFont { std::vector<std::pair<uint32_t, float>> mAxes; }; +struct AFontMatcher { + minikin::FontStyle mFontStyle; + uint32_t mLocaleListId = 0; // 0 is reserved for empty locale ID. + bool mFamilyVariant = AFAMILY_VARIANT_DEFAULT; +}; + +static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_DEFAULT) == + static_cast<uint32_t>(minikin::FamilyVariant::DEFAULT)); +static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_COMPACT) == + static_cast<uint32_t>(minikin::FamilyVariant::COMPACT)); +static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_ELEGANT) == + static_cast<uint32_t>(minikin::FamilyVariant::ELEGANT)); + namespace { std::string xmlTrim(const std::string& in) { @@ -101,7 +116,7 @@ xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) { return nullptr; } -void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, ASystemFont* out, +void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out, const std::string& pathPrefix) { const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang"); XmlCharUniquePtr filePathStr( @@ -197,24 +212,48 @@ void ASystemFontIterator_close(ASystemFontIterator* ite) { delete ite; } -ASystemFont* ASystemFont_matchFamilyStyleCharacter( - const char* _Nonnull familyName, +AFontMatcher* _Nonnull AFontMatcher_create() { + return new AFontMatcher(); +} + +void AFontMatcher_destroy(AFontMatcher* matcher) { + delete matcher; +} + +void AFontMatcher_setStyle( + AFontMatcher* _Nonnull matcher, uint16_t weight, - bool italic, - const char* _Nonnull languageTags, + bool italic) { + matcher->mFontStyle = minikin::FontStyle( + weight, static_cast<minikin::FontStyle::Slant>(italic)); +} + +void AFontMatcher_setLocales( + AFontMatcher* _Nonnull matcher, + const char* _Nonnull languageTags) { + matcher->mLocaleListId = minikin::registerLocaleList(languageTags); +} + +void AFontMatcher_setFamilyVariant(AFontMatcher* _Nonnull matcher, uint32_t familyVariant) { + matcher->mFamilyVariant = familyVariant; +} + +AFont* _Nonnull AFontMatcher_match( + const AFontMatcher* _Nonnull matcher, + const char* _Nonnull familyName, const uint16_t* _Nonnull text, - uint32_t textLength, + const uint32_t textLength, uint32_t* _Nullable runLength) { std::shared_ptr<minikin::FontCollection> fc = minikin::SystemFonts::findFontCollection(familyName); - std::vector<minikin::FontCollection::Run> runs = - fc->itemize(minikin::U16StringPiece(text, textLength), - minikin::FontStyle(weight, static_cast<minikin::FontStyle::Slant>(italic)), - minikin::registerLocaleList(languageTags), - minikin::FamilyVariant::DEFAULT); + std::vector<minikin::FontCollection::Run> runs = fc->itemize( + minikin::U16StringPiece(text, textLength), + matcher->mFontStyle, + matcher->mLocaleListId, + static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant)); const minikin::Font* font = runs[0].fakedFont.font; - std::unique_ptr<ASystemFont> result = std::make_unique<ASystemFont>(); + std::unique_ptr<AFont> result = std::make_unique<AFont>(); const android::MinikinFontSkia* minikinFontSkia = reinterpret_cast<android::MinikinFontSkia*>(font->typeface().get()); result->mFilePath = minikinFontSkia->getFilePath(); @@ -253,7 +292,7 @@ xmlNode* findNextFontNode(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode) { } } -ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) { +AFont* ASystemFontIterator_next(ASystemFontIterator* ite) { LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument"); if (ite->mXmlDoc) { ite->mFontNode = findNextFontNode(ite->mXmlDoc, ite->mFontNode); @@ -262,7 +301,7 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) { ite->mXmlDoc.reset(); ite->mFontNode = nullptr; } else { - std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>(); + std::unique_ptr<AFont> font = std::make_unique<AFont>(); copyFont(ite->mXmlDoc, ite->mFontNode, font.get(), "/system/fonts/"); if (!isFontFileAvailable(font->mFilePath)) { return ASystemFontIterator_next(ite); @@ -279,7 +318,7 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) { ite->mFontNode = nullptr; return nullptr; } else { - std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>(); + std::unique_ptr<AFont> font = std::make_unique<AFont>(); copyFont(ite->mCustomizationXmlDoc, ite->mFontNode, font.get(), "/product/fonts/"); if (!isFontFileAvailable(font->mFilePath)) { return ASystemFontIterator_next(ite); @@ -290,48 +329,48 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) { return nullptr; } -void ASystemFont_close(ASystemFont* font) { +void AFont_close(AFont* font) { delete font; } -const char* ASystemFont_getFontFilePath(const ASystemFont* font) { +const char* AFont_getFontFilePath(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); return font->mFilePath.c_str(); } -uint16_t ASystemFont_getWeight(const ASystemFont* font) { +uint16_t AFont_getWeight(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); return font->mWeight; } -bool ASystemFont_isItalic(const ASystemFont* font) { +bool AFont_isItalic(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument"); return font->mItalic; } -const char* ASystemFont_getLocale(const ASystemFont* font) { +const char* AFont_getLocale(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); return font->mLocale ? nullptr : font->mLocale->c_str(); } -size_t ASystemFont_getCollectionIndex(const ASystemFont* font) { +size_t AFont_getCollectionIndex(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); return font->mCollectionIndex; } -size_t ASystemFont_getAxisCount(const ASystemFont* font) { +size_t AFont_getAxisCount(const AFont* font) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); return font->mAxes.size(); } -uint32_t ASystemFont_getAxisTag(const ASystemFont* font, uint32_t axisIndex) { +uint32_t AFont_getAxisTag(const AFont* font, uint32_t axisIndex) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(), "given axis index is out of bounds. (< %zd", font->mAxes.size()); return font->mAxes[axisIndex].first; } -float ASystemFont_getAxisValue(const ASystemFont* font, uint32_t axisIndex) { +float AFont_getAxisValue(const AFont* font, uint32_t axisIndex) { LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument"); LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(), "given axis index is out of bounds. (< %zd", font->mAxes.size()); diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java index 5650f2125737..bee4bbd9f42d 100644 --- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java +++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java @@ -33,8 +33,8 @@ import android.net.IIpMemoryStore; import android.net.ipmemorystore.Blob; import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; -import android.net.ipmemorystore.IOnNetworkAttributesRetrieved; -import android.net.ipmemorystore.IOnSameNetworkResponseListener; +import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.IOnSameL3NetworkResponseListener; import android.net.ipmemorystore.IOnStatusListener; import android.net.ipmemorystore.NetworkAttributes; import android.net.ipmemorystore.NetworkAttributesParcelable; @@ -297,16 +297,16 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub { */ @Override public void isSameNetwork(@Nullable final String l2Key1, @Nullable final String l2Key2, - @Nullable final IOnSameNetworkResponseListener listener) { + @Nullable final IOnSameL3NetworkResponseListener listener) { if (null == listener) return; mExecutor.execute(() -> { try { if (null == l2Key1 || null == l2Key2) { - listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null); + listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null); return; } if (null == mDb) { - listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null); + listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null); return; } try { @@ -315,16 +315,16 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub { final NetworkAttributes attr2 = IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key2); if (null == attr1 || null == attr2) { - listener.onSameNetworkResponse(makeStatus(SUCCESS), + listener.onSameL3NetworkResponse(makeStatus(SUCCESS), new SameL3NetworkResponse(l2Key1, l2Key2, -1f /* never connected */).toParcelable()); return; } final float confidence = attr1.getNetworkGroupSamenessConfidence(attr2); - listener.onSameNetworkResponse(makeStatus(SUCCESS), + listener.onSameL3NetworkResponse(makeStatus(SUCCESS), new SameL3NetworkResponse(l2Key1, l2Key2, confidence).toParcelable()); } catch (Exception e) { - listener.onSameNetworkResponse(makeStatus(ERROR_GENERIC), null); + listener.onSameL3NetworkResponse(makeStatus(ERROR_GENERIC), null); } } catch (final RemoteException e) { // Client at the other end died @@ -343,7 +343,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub { */ @Override public void retrieveNetworkAttributes(@Nullable final String l2Key, - @Nullable final IOnNetworkAttributesRetrieved listener) { + @Nullable final IOnNetworkAttributesRetrievedListener listener) { if (null == listener) return; mExecutor.execute(() -> { try { diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java index 94cc58919459..a00eff7992d4 100644 --- a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java +++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java @@ -31,8 +31,8 @@ import android.content.Context; import android.net.ipmemorystore.Blob; import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; -import android.net.ipmemorystore.IOnNetworkAttributesRetrieved; -import android.net.ipmemorystore.IOnSameNetworkResponseListener; +import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.IOnSameL3NetworkResponseListener; import android.net.ipmemorystore.IOnStatusListener; import android.net.ipmemorystore.NetworkAttributes; import android.net.ipmemorystore.NetworkAttributesParcelable; @@ -163,9 +163,9 @@ public class IpMemoryStoreServiceTest { private interface OnNetworkAttributesRetrievedListener { void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr); } - private IOnNetworkAttributesRetrieved onNetworkAttributesRetrieved( + private IOnNetworkAttributesRetrievedListener onNetworkAttributesRetrieved( final OnNetworkAttributesRetrievedListener functor) { - return new IOnNetworkAttributesRetrieved() { + return new IOnNetworkAttributesRetrievedListener() { @Override public void onNetworkAttributesRetrieved(final StatusParcelable status, final String l2Key, final NetworkAttributesParcelable attributes) @@ -182,17 +182,17 @@ public class IpMemoryStoreServiceTest { } /** Helper method to make an IOnSameNetworkResponseListener */ - private interface OnSameNetworkResponseListener { - void onSameNetworkResponse(Status status, SameL3NetworkResponse answer); + private interface OnSameL3NetworkResponseListener { + void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer); } - private IOnSameNetworkResponseListener onSameResponse( - final OnSameNetworkResponseListener functor) { - return new IOnSameNetworkResponseListener() { + private IOnSameL3NetworkResponseListener onSameResponse( + final OnSameL3NetworkResponseListener functor) { + return new IOnSameL3NetworkResponseListener() { @Override - public void onSameNetworkResponse(final StatusParcelable status, + public void onSameL3NetworkResponse(final StatusParcelable status, final SameL3NetworkResponseParcelable sameL3Network) throws RemoteException { - functor.onSameNetworkResponse(new Status(status), + functor.onSameL3NetworkResponse(new Status(status), null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network)); } diff --git a/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml b/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml index 9089a930c254..1a4b1c3ebe50 100644 --- a/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml +++ b/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml @@ -20,6 +20,7 @@ android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0" + android:autoMirrored="true" android:tint="?android:attr/colorControlNormal"> <path android:fillColor="#FFFFFFFF" diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index 9feacac60365..eeb6cb015ae6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -75,20 +75,32 @@ public class PowerWhitelistBackend { return true; } + if (isDefaultActiveApp(pkg)) { + return true; + } + + return false; + } + + /** + * Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..) + */ + public boolean isDefaultActiveApp(String pkg) { // Additionally, check if pkg is default dialer/sms. They are considered essential apps and // should be automatically whitelisted (otherwise user may be able to set restriction on // them, leading to bad device behavior.) - if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { - return false; - } + + final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEPHONY); final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext, true /* updateIfNeeded */); - if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) { + if (hasTelephony && defaultSms != null && TextUtils.equals(pkg, + defaultSms.getPackageName())) { return true; } final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext); - if (TextUtils.equals(pkg, defaultDialer)) { + if (hasTelephony && TextUtils.equals(pkg, defaultDialer)) { return true; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index bbf807d29402..44ee423785c2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -118,6 +118,7 @@ public class PowerWhitelistBackendTest { ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue(); + assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testSms)).isTrue(); } @Test @@ -126,6 +127,7 @@ public class PowerWhitelistBackendTest { ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue(); + assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testDialer)).isTrue(); } @Test @@ -133,6 +135,7 @@ public class PowerWhitelistBackendTest { doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE); assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerWhitelistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue(); } @Test diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml index 48094c48aa68..7a68c032d8be 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon.xml @@ -15,5 +15,5 @@ Copyright (C) 2018 The Android Open Source Project --> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@drawable/icon_bg"/> - <foreground android:drawable="@drawable/p"/> + <foreground android:drawable="@drawable/q"/> </adaptive-icon> diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml index 31ecf7edfb11..2a54dfad8191 100644 --- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml +++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml @@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project limitations under the License. --> <color xmlns:android="http://schemas.android.com/apk/res/android" - android:color="#C5E1A5" /> + android:color="#77C360" /> diff --git a/packages/SystemUI/res/drawable-nodpi/p.xml b/packages/SystemUI/res/drawable-nodpi/p.xml deleted file mode 100644 index 596b7824cdb7..000000000000 --- a/packages/SystemUI/res/drawable-nodpi/p.xml +++ /dev/null @@ -1,33 +0,0 @@ -<!-- -Copyright (C) 2018 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="108dp" - android:height="108dp" - android:viewportWidth="108" - android:viewportHeight="108"> - <path - android:pathData="M49,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108" - android:strokeWidth="16" - android:fillColor="#00000000" - android:strokeColor="#7CB342" - android:fillType="evenOdd"/> - <path - android:pathData="M51,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108" - android:strokeWidth="8" - android:fillColor="#00000000" - android:strokeColor="#FFFFFF" - android:fillType="evenOdd"/> -</vector> diff --git a/packages/SystemUI/res/drawable-nodpi/q.xml b/packages/SystemUI/res/drawable-nodpi/q.xml new file mode 100644 index 000000000000..0f42d2e20040 --- /dev/null +++ b/packages/SystemUI/res/drawable-nodpi/q.xml @@ -0,0 +1,40 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108.0" + android:viewportHeight="108.0"> + <group + android:name="scale" + android:pivotX="54" android:pivotY="54" + android:scaleX="0.9" + android:scaleY="0.9"> + <group + android:name="nudge" + android:translateX="24" + android:translateY="23.5"> + <path + android:name="tail" + android:fillColor="#FFFFFF" + android:pathData="M21.749674,34.122784l-9.431964,9.529709l-6.31771,-6.2529106l15.736504,-15.899582l64.765724,65.16436l-6.3046494,6.266083z"/> + <path + android:name="counter" + android:fillColor="#FFFFFF" + android:pathData="M30,9.32352941 C41.6954418,9.32352941 51.1764706,18.8045582 51.1764706,30.5 C51.1764706,42.1954418 41.6954418,51.6764706 30,51.6764706 C18.3045582,51.6764706 8.82352941,42.1954418 8.82352941,30.5 C8.82352941,18.8045582 18.3045582,9.32352941 30,9.32352941 L30,9.32352941 Z M30,0.5 C13.4314575,0.5 -5.53805368e-15,13.9314575 -7.10542736e-15,30.5 C-1.02401747e-14,47.0685425 13.4314575,60.5 30,60.5 C46.5685425,60.5 60,47.0685425 60,30.5 C59.9805514,13.9395201 46.5604799,0.519448617 30,0.5 Z"/> + </group> + </group> +</vector> diff --git a/packages/SystemUI/res/drawable/bubble_flyout.xml b/packages/SystemUI/res/drawable/bubble_flyout.xml new file mode 100644 index 000000000000..5406aaa65372 --- /dev/null +++ b/packages/SystemUI/res/drawable/bubble_flyout.xml @@ -0,0 +1,29 @@ +<!-- + ~ 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 + --> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > + <!-- TODO: Add the triangle pointing to the bubble stack. --> + <item> + <shape android:shape="rectangle"> + <solid android:color="?android:attr/colorBackgroundFloating" /> + <corners + android:bottomLeftRadius="?android:attr/dialogCornerRadius" + android:topLeftRadius="?android:attr/dialogCornerRadius" + android:bottomRightRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="?android:attr/dialogCornerRadius" + /> + </shape> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_notification_gentle.xml b/packages/SystemUI/res/drawable/ic_notification_gentle.xml new file mode 100644 index 000000000000..7074130a63ce --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_notification_gentle.xml @@ -0,0 +1,40 @@ +<!-- +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. +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/back"> + <shape android:shape="oval"> + <solid + android:color="@color/GM2_green_500" /> + <size + android:height="36dp" + android:width="36dp"/> + </shape> + </item> + <item + android:id="@+id/fore" + android:gravity="center"> + <vector + android:width="32dp" + android:height="32dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M15,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5c0,1.38 -1.12,2.5 -2.5,2.5S6.5,13.38 6.5,12c0,-0.28 -0.22,-0.5 -0.5,-0.5c-0.24,0 -0.46,0.18 -0.49,0.42C5.41,12.55 4.89,13 4.27,13H2v-2h1.71C4.1,10.11 5,9.5 6,9.5c1.38,0 2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5c1.02,0 1.91,0.6 2.29,1.5H22v2h-2.27c-0.62,0 -1.14,-0.45 -1.23,-1.08c-0.04,-0.24 -0.25,-0.42 -0.49,-0.42c-0.28,0 -0.5,0.22 -0.5,0.5C17.5,13.38 16.38,14.5 15,14.5z"/> + </vector> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/ic_notification_interruptive.xml b/packages/SystemUI/res/drawable/ic_notification_interruptive.xml new file mode 100644 index 000000000000..0a8b3b8fa775 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_notification_interruptive.xml @@ -0,0 +1,41 @@ +<!-- +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. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/back"> + <shape android:shape="oval"> + <solid + android:color="@color/GM2_yellow_500" /> + <size + android:height="36dp" + android:width="36dp"/> + </shape> + </item> + <item + android:id="@+id/fore" + android:gravity="center"> + <vector + android:width="32dp" + android:height="32dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M8.98,16.65c-0.47,0 -0.91,-0.27 -1.12,-0.69l-1.93,-4.61L5.46,12.3c-0.21,0.43 -0.64,0.69 -1.12,0.69H2v-2h1.88l1,-2C5.1,8.56 5.52,8.3 6,8.3s0.9,0.26 1.12,0.69l1.73,4.14l2,-7c0.2,-0.46 0.65,-0.76 1.15,-0.76s0.95,0.3 1.15,0.76l0.04,0.12l1.96,6.88l1.7,-4.08c0.49,-0.98 1.84,-0.91 2.26,-0.06l1,2H22v2h-2.35c-0.47,0 -0.91,-0.27 -1.12,-0.7l-0.47,-0.95l-1.9,4.55c-0.25,0.5 -0.69,0.77 -1.18,0.75c-0.48,-0.01 -0.92,-0.31 -1.11,-0.76l-0.04,-0.12L12,9.37l-1.87,6.52c-0.19,0.45 -0.63,0.74 -1.11,0.76C9.01,16.65 9,16.65 8.98,16.65zM20.32,11.4L20.32,11.4C20.32,11.4 20.32,11.4 20.32,11.4z" /> + </vector> + </item> +</layer-list> diff --git a/packages/SystemUI/res/layout/bubble_flyout.xml b/packages/SystemUI/res/layout/bubble_flyout.xml new file mode 100644 index 000000000000..74c6c123479c --- /dev/null +++ b/packages/SystemUI/res/layout/bubble_flyout.xml @@ -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 + --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/bubble_flyout" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:background="@drawable/bubble_flyout" + android:padding="@dimen/bubble_flyout_padding" + android:translationZ="@dimen/bubble_flyout_elevation"> + + <TextView + android:id="@+id/bubble_flyout_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxLines="2" + android:maxWidth="@dimen/bubble_flyout_maxwidth" + android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" /> + +</FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/packages/SystemUI/res/layout/bubble_view.xml index 13186fc6437c..a8eb2914b0b2 100644 --- a/packages/SystemUI/res/layout/bubble_view.xml +++ b/packages/SystemUI/res/layout/bubble_view.xml @@ -27,12 +27,4 @@ android:padding="@dimen/bubble_view_padding" android:clipToPadding="false"/> - <TextView - android:id="@+id/message_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:minWidth="@dimen/bubble_message_min_width" - android:maxWidth="@dimen/bubble_message_max_width" - android:padding="@dimen/bubble_message_padding"/> - </com.android.systemui.bubbles.BubbleView> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 0d44931463bd..f7c6c435d258 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -24,6 +24,7 @@ android:clipChildren="false" android:clipToPadding="false" android:orientation="vertical" + android:paddingStart="@*android:dimen/notification_content_margin_start" android:background="@color/notification_guts_bg_color"> <!-- Package Info --> @@ -31,7 +32,6 @@ android:id="@+id/header" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginStart="@*android:dimen/notification_content_margin_start" android:clipChildren="false" android:clipToPadding="false"> <ImageView @@ -44,7 +44,7 @@ android:id="@+id/pkgname" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" + style="@style/TextAppearance.NotificationInfo.Primary" android:layout_marginStart="3dp" android:layout_marginEnd="2dp" android:singleLine="true" @@ -54,7 +54,7 @@ android:id="@+id/pkg_divider" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" + style="@style/TextAppearance.NotificationInfo.Primary" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:text="@*android:string/notification_header_divider_symbol" @@ -64,7 +64,7 @@ android:id="@+id/delegate_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info" + style="@style/TextAppearance.NotificationInfo.Primary" android:layout_marginStart="2dp" android:layout_marginEnd="2dp" android:ellipsize="end" @@ -77,286 +77,284 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_alignParentEnd="true" - android:paddingHorizontal="16dp" + android:orientation="horizontal"> <!-- Optional link to app. Only appears if the channel is not disabled and the app asked for it --> <ImageButton android:id="@+id/app_settings" - android:layout_width="40dp" - android:layout_height="56dp" + android:layout_width="48dp" + android:layout_height="48dp" android:layout_centerVertical="true" - android:paddingRight="16dp" android:visibility="gone" android:background="@drawable/ripple_drawable" android:contentDescription="@string/notification_app_settings" - android:src="@drawable/ic_settings" - android:tint="?android:attr/colorAccent" /> + android:src="@drawable/ic_info" + android:tint="@color/notification_guts_link_icon_tint" /> <!-- 24 dp icon with 16 dp padding all around to mirror notification content margins --> <ImageButton android:id="@+id/info" - android:layout_width="24dp" - android:layout_height="56dp" + android:layout_width="48dp" + android:layout_height="48dp" android:layout_centerVertical="true" android:background="@drawable/ripple_drawable" android:contentDescription="@string/notification_more_settings" - android:src="@drawable/ic_info" - android:tint="?android:attr/colorAccent" /> + android:src="@drawable/ic_settings" + android:tint="@color/notification_guts_link_icon_tint" /> </LinearLayout> </RelativeLayout> + <!-- Channel Info Block --> <LinearLayout - android:id="@+id/prompt" + android:id="@+id/channel_info" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="@dimen/notification_guts_button_spacing" - android:clipChildren="false" - android:clipToPadding="false" + android:paddingEnd="@*android:dimen/notification_content_margin_end" android:orientation="vertical"> - - <!-- Channel Info Block --> - <LinearLayout + <RelativeLayout + android:id="@+id/names" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="@*android:dimen/notification_content_margin_start" - android:layout_marginEnd="@*android:dimen/notification_content_margin_start" - android:orientation="vertical"> - <RelativeLayout - android:id="@+id/names" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - <TextView - android:id="@+id/group_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" - android:layout_marginStart="2dp" - android:layout_marginEnd="2dp" - android:ellipsize="end" - android:maxLines="1" - android:layout_centerVertical="true" /> - <TextView - android:id="@+id/pkg_group_divider" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" - android:layout_marginStart="2dp" - android:layout_marginEnd="2dp" - android:text="@*android:string/notification_header_divider_symbol" - android:layout_centerVertical="true" - android:layout_toEndOf="@id/group_name" /> - <!-- Channel Name --> - <TextView - android:id="@+id/channel_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_weight="1" - style="@*android:style/TextAppearance.DeviceDefault.Notification.Title" - android:layout_toEndOf="@id/pkg_group_divider"/> - </RelativeLayout> - <!-- Question prompt --> + android:layout_height="wrap_content"> <TextView - android:id="@+id/block_prompt" + android:id="@+id/group_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@*android:style/TextAppearance.DeviceDefault.Notification" /> - </LinearLayout> + style="@style/TextAppearance.NotificationInfo.Primary" + android:layout_marginStart="2dp" + android:layout_marginEnd="2dp" + android:ellipsize="end" + android:maxLines="1" + android:layout_centerVertical="true" /> + <TextView + android:id="@+id/pkg_group_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/TextAppearance.NotificationInfo.Primary" + android:layout_marginStart="2dp" + android:layout_marginEnd="2dp" + android:text="@*android:string/notification_header_divider_symbol" + android:layout_centerVertical="true" + android:layout_toEndOf="@id/group_name" /> + <!-- Channel Name --> + <TextView + android:id="@+id/channel_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="1" + style="@style/TextAppearance.NotificationInfo.Primary" + android:layout_toEndOf="@id/pkg_group_divider"/> + </RelativeLayout> + </LinearLayout> - <!-- Settings and Done buttons --> + <LinearLayout + android:id="@+id/blocking_helper" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/notification_guts_button_spacing" + android:paddingEnd="@*android:dimen/notification_content_margin_end" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical"> + <!-- blocking helper text. no need for non-configurable check b/c controls won't be + activated in that case --> + <TextView + android:id="@+id/blocking_helper_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="2dp" + android:text="@string/inline_blocking_helper" + style="@*android:style/TextAppearance.DeviceDefault.Notification" /> <RelativeLayout - android:id="@+id/block_or_minimize" + android:id="@+id/block_buttons" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@dimen/notification_guts_button_spacing" - android:layout_marginStart="@dimen/notification_guts_button_side_margin" - android:layout_marginEnd="@dimen/notification_guts_button_side_margin" - android:clipChildren="false" - android:clipToPadding="false"> + android:layout_marginTop="@dimen/notification_guts_button_spacing"> <TextView - android:id="@+id/done" - android:text="@string/inline_ok_button" + android:id="@+id/blocking_helper_turn_off_notifications" + android:text="@string/inline_turn_off_notifications" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" - android:maxWidth="100dp" + android:layout_alignParentStart="true" + android:width="110dp" + android:paddingEnd="15dp" + android:breakStrategy="simple" style="@style/TextAppearance.NotificationInfo.Button"/> - - <LinearLayout - android:id="@+id/block_buttons" + <TextView + android:id="@+id/deliver_silently" + android:text="@string/inline_deliver_silently_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" + android:paddingEnd="15dp" + android:width="110dp" + android:breakStrategy="simple" + android:layout_toStartOf="@+id/keep_showing" + style="@style/TextAppearance.NotificationInfo.Button"/> + <TextView + android:id="@+id/keep_showing" + android:text="@string/inline_keep_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" + android:width="110dp" + android:breakStrategy="simple" android:layout_alignParentEnd="true" - android:maxWidth="200dp" - android:orientation="horizontal"> - <TextView - android:id="@+id/deliver_silently" - android:text="@string/inline_silent_button_silent" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - android:paddingRight="24dp" - android:maxWidth="125dp" - style="@style/TextAppearance.NotificationInfo.Button"/> - <TextView - android:id="@+id/block" - android:text="@string/inline_block_button" - android:minWidth="48dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:maxWidth="75dp" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - style="@style/TextAppearance.NotificationInfo.Button"/> - <TextView - android:id="@+id/minimize" - android:text="@string/inline_minimize_button" - android:minWidth="48dp" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:maxWidth="75dp" - android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing" - style="@style/TextAppearance.NotificationInfo.Button"/> - </LinearLayout> + style="@style/TextAppearance.NotificationInfo.Button"/> </RelativeLayout> + + </LinearLayout> + + <LinearLayout + android:id="@+id/inline_controls" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/notification_guts_button_spacing" + android:paddingEnd="@*android:dimen/notification_content_margin_end" + android:clipChildren="false" + android:clipToPadding="false" + android:orientation="vertical"> + + <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings--> + <TextView + android:id="@+id/non_configurable_text" + android:text="@string/notification_unblockable_desc" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/notification_guts_option_vertical_padding" + style="@*android:style/TextAppearance.DeviceDefault.Notification" /> + + <!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings--> + <TextView + android:id="@+id/non_configurable_multichannel_text" + android:text="@string/notification_multichannel_desc" + android:visibility="gone" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/notification_guts_option_vertical_padding" + style="@*android:style/TextAppearance.DeviceDefault.Notification" /> + <LinearLayout android:id="@+id/interruptiveness_settings" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical" - android:visibility="gone"> + android:orientation="vertical"> + <!-- Interruptive row --> <LinearLayout + android:id="@+id/alert_row" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="2dp" - android:layout_marginStart="@dimen/notification_guts_button_side_margin" - android:layout_marginEnd="@dimen/notification_guts_button_side_margin" - android:gravity="center" + android:paddingTop="@dimen/notification_guts_option_vertical_padding" + android:paddingBottom="@dimen/notification_guts_option_vertical_padding" + android:paddingStart="@dimen/notification_guts_option_horizontal_padding" android:orientation="horizontal"> + + <ImageView + android:id="@+id/int_alert" + android:src="@drawable/ic_notification_interruptive" + android:background="@android:color/transparent" + android:layout_gravity="center" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:contentDescription="@string/inline_silent_button_alert"/> + <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="@dimen/notification_guts_option_horizontal_padding" + android:paddingEnd="@dimen/notification_guts_option_horizontal_padding" android:orientation="vertical"> - <FrameLayout - android:id="@+id/int_block_wrapper" - android:padding="4dp" - android:layout_width="48dp" - android:layout_height="48dp" - android:gravity="center"> - <ImageButton - android:id="@+id/int_block" - android:background="@drawable/circle_white_40dp" - android:src="@drawable/ic_notification_block" - android:layout_gravity="center" - android:layout_width="40dp" - android:layout_height="40dp" - android:clickable="false" - android:contentDescription="@string/inline_block_button" - android:tint="@color/GM2_grey_400" - style="@style/TextAppearance.NotificationInfo.Button"/> - </FrameLayout> <TextView - android:id="@+id/int_block_label" - android:text="@string/inline_block_button" - android:layout_gravity="center_horizontal" - android:gravity="center" + android:id="@+id/int_alert_label" + android:text="@string/inline_silent_button_alert" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="1" - style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> + style="@style/TextAppearance.NotificationInfo.Primary"/> + <TextView + android:id="@+id/int_alert_summary" + android:text="@string/hint_text_alert" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + style="@style/TextAppearance.NotificationInfo.Secondary"/> </LinearLayout> + </LinearLayout> + + <!-- Gentle row --> + <LinearLayout + android:id="@+id/silent_row" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/notification_guts_option_vertical_padding" + android:paddingBottom="@dimen/notification_guts_option_vertical_padding" + android:paddingStart="@dimen/notification_guts_option_horizontal_padding" + android:layout_marginTop="@dimen/notification_guts_option_vertical_margin" + android:orientation="horizontal"> + <ImageView + android:id="@+id/int_silent" + android:src="@drawable/ic_notification_gentle" + android:layout_gravity="center" + android:layout_width="36dp" + android:layout_height="36dp" + android:background="@android:color/transparent" + android:contentDescription="@string/inline_silent_button_silent"/> <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_horizontal" - android:orientation="vertical"> - <FrameLayout - android:id="@+id/int_silent_wrapper" - android:padding="4dp" - android:layout_width="48dp" - android:layout_height="48dp" - android:gravity="center"> - <ImageButton - android:id="@+id/int_silent" - android:background="@drawable/circle_white_40dp" - android:src="@drawable/ic_notifications_silence" - android:layout_gravity="center" - android:layout_width="40dp" - android:layout_height="40dp" - android:clickable="false" - android:contentDescription="@string/inline_silent_button_silent" - android:tint="@color/GM2_grey_400" - style="@style/TextAppearance.NotificationInfo.Button"/> - </FrameLayout> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingStart="@dimen/notification_guts_option_horizontal_padding" + android:paddingEnd="@dimen/notification_guts_option_horizontal_padding"> <TextView android:id="@+id/int_silent_label" android:text="@string/inline_silent_button_silent" - android:layout_gravity="center_horizontal" - android:gravity="center" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="1" - style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> - </LinearLayout> - <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_horizontal" - android:orientation="vertical"> - <FrameLayout - android:id="@+id/int_alert_wrapper" - android:padding="4dp" - android:layout_width="48dp" - android:layout_height="48dp" - android:gravity="center"> - <ImageButton - android:id="@+id/int_alert" - android:background="@drawable/circle_white_40dp" - android:src="@drawable/ic_notifications_alert" - android:layout_gravity="center" - android:layout_width="40dp" - android:layout_height="40dp" - android:contentDescription="@string/inline_silent_button_alert" - android:clickable="false" - android:tint="@color/GM2_grey_400" - style="@style/TextAppearance.NotificationInfo.Button"/> - </FrameLayout> + style="@style/TextAppearance.NotificationInfo.Primary"/> <TextView - android:id="@+id/int_alert_label" - android:text="@string/inline_silent_button_alert" - android:layout_gravity="center_horizontal" - android:gravity="center" + android:id="@+id/int_silent_summary" + android:text="@string/hint_text_silent" android:layout_width="match_parent" android:layout_height="wrap_content" android:ellipsize="end" - android:maxLines="1" - style="@style/TextAppearance.NotificationInfo.ButtonLabel"/> + style="@style/TextAppearance.NotificationInfo.Secondary"/> </LinearLayout> </LinearLayout> + </LinearLayout> + + <RelativeLayout + android:id="@+id/bottom_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/notification_guts_button_spacing" + android:paddingBottom="@dimen/notification_guts_button_spacing"> <TextView - android:id="@+id/hint_text" - android:layout_marginStart="@*android:dimen/notification_content_margin_start" - android:layout_marginEnd="@*android:dimen/notification_content_margin_start" + android:id="@+id/turn_off_notifications" + android:text="@string/inline_turn_off_notifications" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/TextAppearance.NotificationInfo.HintText" /> + android:layout_centerVertical="true" + android:layout_alignParentStart="true" + android:maxWidth="200dp" + style="@style/TextAppearance.NotificationInfo.Button"/> <TextView - android:id="@+id/done_button" + android:id="@+id/done" + android:text="@string/inline_ok_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="right" - android:paddingRight="24dp" - android:text="@string/inline_done_button" - style="@style/TextAppearance.NotificationInfo.Button" /> - </LinearLayout> + android:layout_centerVertical="true" + android:maxWidth="125dp" + android:layout_alignParentEnd="true" + style="@style/TextAppearance.NotificationInfo.Button"/> + </RelativeLayout> + </LinearLayout> <com.android.systemui.statusbar.notification.row.NotificationUndoLayout diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml index d74d25846e3c..8a0aaea77d52 100644 --- a/packages/SystemUI/res/values-night/colors.xml +++ b/packages/SystemUI/res/values-night/colors.xml @@ -42,6 +42,10 @@ <!-- The color of the text inside a notification --> <color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color> + <color name="notification_guts_selection_bg">#202124</color> + <color name="notification_guts_selection_border">#669DF6</color> + <color name="notification_guts_link_icon_tint">@color/GM2_grey_200</color> + <!-- The color of the background in the top part of QSCustomizer --> <color name="qs_customize_background">@color/GM2_grey_900</color> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 290d75b4de9c..b2a507549cce 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -88,6 +88,10 @@ <!-- The "inside" of a notification, reached via longpress --> <color name="notification_guts_bg_color">@color/GM2_grey_50</color> + <color name="notification_guts_selection_bg">#FFFFFF</color> + <color name="notification_guts_selection_border">#4285F4</color> + <color name="notification_guts_link_icon_tint">@color/GM2_grey_900</color> + <color name="assist_orb_color">#ffffff</color> <color name="keyguard_user_switcher_background_gradient_color">#77000000</color> @@ -163,4 +167,7 @@ <color name="GM2_red_300">#F28B82</color> <color name="GM2_red_500">#B71C1C</color> + + <color name="GM2_yellow_500">#FFFBBC04</color> + <color name="GM2_green_500">#FF34A853</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index f8295ebff027..b0afe75ebc68 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -109,12 +109,12 @@ <!-- The default tiles to display in QuickSettings --> <string name="quick_settings_tiles_default" translatable="false"> - wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy + wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast </string> <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,sensorprivacy + wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night </string> <!-- The tiles to display in QuickSettings --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 1c97f489846c..a02469ee9fb9 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -179,7 +179,7 @@ <dimen name="notification_menu_icon_padding">20dp</dimen> <!-- The vertical space around the buttons in the inline settings --> - <dimen name="notification_guts_button_spacing">6dp</dimen> + <dimen name="notification_guts_button_spacing">12dp</dimen> <!-- Extra horizontal space for properly aligning guts buttons with the notification content --> <dimen name="notification_guts_button_side_margin">8dp</dimen> @@ -196,6 +196,18 @@ <!-- The height of the header in inline settings --> <dimen name="notification_guts_header_height">24dp</dimen> + <!-- The text size of the header in inline settings --> + <dimen name="notification_guts_header_text_size">16sp</dimen> + + <!-- The horizontal space between items in the alert selections in the inline settings --> + <dimen name="notification_guts_option_horizontal_padding">15dp</dimen> + + <!-- The vertical space between items in the alert selections in the inline settings --> + <dimen name="notification_guts_option_vertical_padding">15dp</dimen> + + <!-- The vertical space between the alert selections in the inline settings --> + <dimen name="notification_guts_option_vertical_margin">6dp</dimen> + <!-- The minimum height for the snackbar shown after the snooze option has been chosen. --> <dimen name="snooze_snackbar_min_height">56dp</dimen> @@ -1035,6 +1047,12 @@ <!-- How much each bubble is elevated. --> <dimen name="bubble_elevation">1dp</dimen> + <!-- How much the bubble flyout text container is elevated. --> + <dimen name="bubble_flyout_elevation">4dp</dimen> + <!-- How much padding is around the flyout text. --> + <dimen name="bubble_flyout_padding">16dp</dimen> + <!-- The maximum width of a bubble flyout. --> + <dimen name="bubble_flyout_maxwidth">200dp</dimen> <!-- Padding around a collapsed bubble --> <dimen name="bubble_view_padding">0dp</dimen> <!-- Padding between bubbles when displayed in expanded state --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 0411d015fd63..f47d4b5aac6d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -670,6 +670,9 @@ <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> more notifications inside.</item> </plurals> + <!-- Format to use to summarize a message from a contact in a single line of text. For example: "Julia: How's it going?". [CHAR LIMIT=NONE] --> + <string name="notification_summary_message_format"><xliff:g id="contact_name" example="Julia">%1$s</xliff:g>: <xliff:g id="message_content" example="How is it going?">%2$s</xliff:g></string> + <!-- Content description of button in notification inspector for system settings relating to notifications from this application [CHAR LIMIT=NONE] --> <string name="status_bar_notification_inspect_item_title">Notification settings</string> @@ -1599,7 +1602,7 @@ <string name="inline_done_button">Done</string> <!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] --> - <string name="inline_ok_button">OK</string> + <string name="inline_ok_button">Apply</string> <!-- Notification Inline controls: continue receiving notifications prompt, channel level --> <string name="inline_keep_showing">Keep showing these notifications?</string> @@ -1620,17 +1623,20 @@ <string name="inline_minimize_button">Minimize</string> <!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] --> - <string name="inline_silent_button_silent">Show silently</string> + <string name="inline_silent_button_silent">Gentle</string> <!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] --> <string name="inline_silent_button_stay_silent">Stay silent</string> <!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] --> - <string name="inline_silent_button_alert">Alert</string> + <string name="inline_silent_button_alert">Interruptive</string> <!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] --> <string name="inline_silent_button_keep_alerting">Keep alerting</string> + <!-- Notification inline controls: button to show block screen [CHAR_LIMIT=35] --> + <string name="inline_turn_off_notifications">Turn off notifications</string> + <!-- Notification Inline controls: continue receiving notifications prompt, app level --> <string name="inline_keep_showing_app">Keep showing notifications from this app?</string> @@ -1641,11 +1647,14 @@ <string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string> <!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]--> - <string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string> + <string name="hint_text_alert">These notifications will make a sound and show in the notification drawer, status bar, and lock screen</string> <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be turned off</string> + <!-- Notification: Control panel: label that displays when viewing settings for a group of notifications posted to multiple channels. --> + <string name="notification_multichannel_desc">This group of notifications cannot be configured here</string> + <!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for --> <string name="notification_delegate_header">via <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string> @@ -2401,5 +2410,4 @@ <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string> <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]--> <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string> - </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 7c123eff2044..2ff481f7c8fd 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -435,6 +435,7 @@ </style> <style name="TextAppearance.NotificationInfo.Primary"> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> <item name="android:textSize">16sp</item> <item name="android:alpha">0.87</item> </style> @@ -471,16 +472,12 @@ </style> <style name="TextAppearance.NotificationInfo.Button"> - <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> - <item name="android:textSize">14sp</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> + <item name="android:textSize">16sp</item> <item name="android:textColor">?android:attr/colorAccent</item> <item name="android:background">@drawable/btn_borderless_rect</item> <item name="android:gravity">center</item> <item name="android:focusable">true</item> - <item name="android:paddingTop">@dimen/notification_guts_button_vertical_padding</item> - <item name="android:paddingBottom">@dimen/notification_guts_button_vertical_padding</item> - <item name="android:paddingLeft">@dimen/notification_guts_button_horizontal_padding</item> - <item name="android:paddingRight">@dimen/notification_guts_button_horizontal_padding</item> </style> <style name="TextAppearance.HeadsUpStatusBarText" diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 7e935e3a26a5..1076e73d1072 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -24,6 +24,8 @@ import android.content.Context; import android.content.res.Resources; import android.view.WindowManagerPolicyConstants; +import com.android.internal.policy.ScreenDecorationsUtils; + /** * Various shared constants between Launcher and SysUI as part of quickstep */ @@ -130,5 +132,19 @@ public class QuickStepContract { com.android.internal.R.dimen.config_backGestureInset); } + /** + * Corner radius that should be used on windows in order to cover the display. + * These values are expressed in pixels because they should not respect display or font + * scaling, this means that we don't have to reload them on config changes. + */ + public static float getWindowCornerRadius(Resources resources) { + return ScreenDecorationsUtils.getWindowCornerRadius(resources); + } + /** + * If live rounded corners are supported on windows. + */ + public static boolean supportsRoundedCornersOnWindows(Resources resources) { + return ScreenDecorationsUtils.supportsRoundedCornersOnWindows(resources); + } } diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index 72ab02c21192..822538b0ac0a 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -561,4 +561,29 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable { inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(), 0, getBottom() - mList.getBottom()); }; + + private float getAnimationDistance() { + return getContext().getResources().getDimension( + com.android.systemui.R.dimen.global_actions_panel_width) / 2; + } + + @Override + public float getAnimationOffsetX() { + if (RotationUtils.getRotation(mContext) == ROTATION_NONE) { + return getAnimationDistance(); + } + return 0; + } + + @Override + public float getAnimationOffsetY() { + switch (RotationUtils.getRotation(getContext())) { + case RotationUtils.ROTATION_LANDSCAPE: + return -getAnimationDistance(); + case RotationUtils.ROTATION_SEASCAPE: + return getAnimationDistance(); + default: // Portrait + return 0; + } + } }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java index d063a0f4086e..a30b681ed7cc 100644 --- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java +++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java @@ -148,6 +148,16 @@ public abstract class MultiListLayout extends LinearLayout { } /** + * Get the X offset in pixels for use when animating the view onto or off of the screen. + */ + public abstract float getAnimationOffsetX(); + + /** + * Get the Y offset in pixels for use when animating the view onto or off of the screen. + */ + public abstract float getAnimationOffsetY(); + + /** * Adapter class for converting items into child views for MultiListLayout and handling * callbacks for input events. */ diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index be55829869eb..de4605b55272 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -42,7 +42,9 @@ import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.animation.AccelerateDecelerateInterpolator; import android.widget.FrameLayout; +import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.Nullable; @@ -70,6 +72,13 @@ public class BubbleStackView extends FrameLayout { private static final String TAG = "BubbleStackView"; private static final boolean DEBUG = false; + /** Duration of the flyout alpha animations. */ + private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100; + + /** How long to wait, in milliseconds, before hiding the flyout. */ + @VisibleForTesting + static final int FLYOUT_HIDE_AFTER = 5000; + /** * Interface to synchronize {@link View} state and the screen. * @@ -119,6 +128,14 @@ public class BubbleStackView extends FrameLayout { private FrameLayout mExpandedViewContainer; + private View mFlyout; + private TextView mFlyoutText; + /** Spring animation for the flyout. */ + private SpringAnimation mFlyoutSpring; + /** Runnable that fades out the flyout and then sets it to GONE. */ + private Runnable mHideFlyout = + () -> mFlyout.animate().alpha(0f).withEndAction(() -> mFlyout.setVisibility(GONE)); + private int mBubbleSize; private int mBubblePadding; private int mExpandedAnimateXDistance; @@ -131,6 +148,9 @@ public class BubbleStackView extends FrameLayout { private boolean mIsExpanded; private boolean mImeVisible; + /** Whether the stack is currently being dragged. */ + private boolean mIsDragging = false; + private BubbleTouchHandler mTouchHandler; private BubbleController.BubbleExpandListener mExpandListener; private BubbleExpandedView.OnBubbleBlockedListener mBlockedListener; @@ -221,6 +241,17 @@ public class BubbleStackView extends FrameLayout { mExpandedViewContainer.setClipChildren(false); addView(mExpandedViewContainer); + mFlyout = mInflater.inflate(R.layout.bubble_flyout, this, false); + mFlyout.setVisibility(GONE); + mFlyout.animate() + .setDuration(FLYOUT_ALPHA_ANIMATION_DURATION) + .setInterpolator(new AccelerateDecelerateInterpolator()); + addView(mFlyout); + + mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text); + + mFlyoutSpring = new SpringAnimation(mFlyout, DynamicAnimation.TRANSLATION_X); + mExpandedViewXAnim = new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X); mExpandedViewXAnim.setSpring( @@ -448,6 +479,8 @@ public class BubbleStackView extends FrameLayout { requestUpdate(); logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED); + + animateInFlyoutForBubble(b); } /** @@ -549,6 +582,7 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.moveViewTo(b.iconView, 0); } requestUpdate(); + animateInFlyoutForBubble(b /* bubble */); } if (mIsExpanded && entry.equals(mExpandedBubble.entry)) { entry.setShowInShadeWhenBubble(false); @@ -577,11 +611,18 @@ public class BubbleStackView extends FrameLayout { } // Outside parts of view we care about. return null; + } else if (isIntersecting(mFlyout, x, y)) { + return mFlyout; } - // If we're collapsed, the stack is always the target. + + // If it wasn't an individual bubble in the expanded state, or the flyout, it's the stack. return this; } + public View getFlyoutView() { + return mFlyout; + } + /** * Collapses the stack of bubbles. * <p> @@ -622,6 +663,8 @@ public class BubbleStackView extends FrameLayout { */ private void animateExpansion(boolean shouldExpand) { if (mIsExpanded != shouldExpand) { + hideFlyoutImmediate(); + mIsExpanded = shouldExpand; updateExpandedBubble(); applyCurrentState(); @@ -735,6 +778,9 @@ public class BubbleStackView extends FrameLayout { mStackAnimationController.cancelStackPositionAnimations(); mBubbleContainer.setController(mStackAnimationController); + hideFlyoutImmediate(); + + mIsDragging = true; } void onDragged(float x, float y) { @@ -747,6 +793,7 @@ public class BubbleStackView extends FrameLayout { void onDragFinish(float x, float y, float velX, float velY) { // TODO: Add fling to bottom to dismiss. + mIsDragging = false; if (mIsExpanded || mIsExpansionAnimating) { return; @@ -797,6 +844,47 @@ public class BubbleStackView extends FrameLayout { } } + /** + * Animates in the flyout for the given bubble, if available, and then hides it after some time. + */ + @VisibleForTesting + void animateInFlyoutForBubble(Bubble bubble) { + final CharSequence updateMessage = bubble.entry.getUpdateMessage(getContext()); + + // Show the message if one exists, and we're not expanded or animating expansion. + if (updateMessage != null && !isExpanded() && !mIsExpansionAnimating && !mIsDragging) { + final PointF stackPos = mStackAnimationController.getStackPosition(); + + mFlyoutText.setText(updateMessage); + mFlyout.measure(WRAP_CONTENT, WRAP_CONTENT); + mFlyout.post(() -> { + final boolean onLeft = mStackAnimationController.isStackOnLeftSide(); + final float destinationX = onLeft + ? stackPos.x + mBubbleSize + mBubblePadding + : stackPos.x - mFlyout.getMeasuredWidth(); + + // Translate towards the stack slightly, then spring out from the stack. + mFlyout.setTranslationX(destinationX + (onLeft ? -mBubblePadding : mBubblePadding)); + mFlyout.setTranslationY(stackPos.y); + mFlyout.setAlpha(0f); + + mFlyout.setVisibility(VISIBLE); + + mFlyout.animate().alpha(1f); + mFlyoutSpring.animateToFinalPosition(destinationX); + + mFlyout.removeCallbacks(mHideFlyout); + mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER); + }); + } + } + + /** Hide the flyout immediately and cancel any pending hide runnables. */ + private void hideFlyoutImmediate() { + mFlyout.removeCallbacks(mHideFlyout); + mHideFlyout.run(); + } + @Override public void getBoundsOnScreen(Rect outRect) { if (!mIsExpanded) { @@ -806,6 +894,12 @@ public class BubbleStackView extends FrameLayout { } else { mBubbleContainer.getBoundsOnScreen(outRect); } + + if (mFlyout.getVisibility() == View.VISIBLE) { + final Rect flyoutBounds = new Rect(); + mFlyout.getBoundsOnScreen(flyoutBounds); + outRect.union(flyoutBounds); + } } private int getStatusBarHeight() { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java index a7170d0256e3..baeedaacdd95 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java @@ -86,6 +86,7 @@ class BubbleTouchHandler implements View.OnTouchListener { } final boolean isStack = mStack.equals(mTouchedView); + final boolean isFlyout = mStack.getFlyoutView().equals(mTouchedView); final float rawX = event.getRawX(); final float rawY = event.getRawY(); @@ -96,14 +97,18 @@ class BubbleTouchHandler implements View.OnTouchListener { case MotionEvent.ACTION_DOWN: trackMovement(event); - mDismissViewController.createDismissTarget(); - mHandler.postDelayed(mShowDismissAffordance, SHOW_TARGET_DELAY); - mTouchDown.set(rawX, rawY); + if (!isFlyout) { + mDismissViewController.createDismissTarget(); + mHandler.postDelayed(mShowDismissAffordance, SHOW_TARGET_DELAY); + } + if (isStack) { mViewPositionOnTouchDown.set(mStack.getStackPosition()); mStack.onDragStart(); + } else if (isFlyout) { + // TODO(b/129768381): Make the flyout dismissable with a gesture. } else { mViewPositionOnTouchDown.set( mTouchedView.getTranslationX(), mTouchedView.getTranslationY()); @@ -123,6 +128,8 @@ class BubbleTouchHandler implements View.OnTouchListener { if (mMovedEnough) { if (isStack) { mStack.onDragged(viewX, viewY); + } else if (isFlyout) { + // TODO(b/129768381): Make the flyout dismissable with a gesture. } else { mStack.onBubbleDragged(mTouchedView, viewX, viewY); } @@ -141,6 +148,11 @@ class BubbleTouchHandler implements View.OnTouchListener { trackMovement(event); if (mInDismissTarget && isStack) { mController.dismissStack(BubbleController.DISMISS_USER_GESTURE); + } else if (isFlyout) { + // TODO(b/129768381): Expand if tapped, dismiss if swiped away. + if (!mStack.isExpanded() && !mMovedEnough) { + mStack.expandStack(); + } } else if (mMovedEnough) { mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000); final float velX = mVelocityTracker.getXVelocity(); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 3b9164d60c5c..84b86bf9b69f 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -27,7 +27,6 @@ import android.graphics.drawable.Icon; import android.graphics.drawable.InsetDrawable; import android.util.AttributeSet; import android.widget.FrameLayout; -import android.widget.TextView; import com.android.internal.graphics.ColorUtils; import com.android.systemui.Interpolators; @@ -49,7 +48,6 @@ public class BubbleView extends FrameLayout { private Context mContext; private BadgedImageView mBadgedImageView; - private TextView mMessageView; private int mPadding; private int mIconInset; @@ -78,10 +76,7 @@ public class BubbleView extends FrameLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - mBadgedImageView = (BadgedImageView) findViewById(R.id.bubble_image); - mMessageView = (TextView) findViewById(R.id.message_view); - mMessageView.setVisibility(GONE); - mMessageView.setPivotX(0); + mBadgedImageView = findViewById(R.id.bubble_image); } @Override @@ -89,33 +84,6 @@ public class BubbleView extends FrameLayout { super.onAttachedToWindow(); } - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - measureChild(mBadgedImageView, widthSpec, heightSpec); - measureChild(mMessageView, widthSpec, heightSpec); - boolean messageGone = mMessageView.getVisibility() == GONE; - int imageHeight = mBadgedImageView.getMeasuredHeight(); - int imageWidth = mBadgedImageView.getMeasuredWidth(); - int messageHeight = messageGone ? 0 : mMessageView.getMeasuredHeight(); - int messageWidth = messageGone ? 0 : mMessageView.getMeasuredWidth(); - setMeasuredDimension( - getPaddingStart() + imageWidth + mPadding + messageWidth + getPaddingEnd(), - getPaddingTop() + Math.max(imageHeight, messageHeight) + getPaddingBottom()); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - left = getPaddingStart(); - top = getPaddingTop(); - int imageWidth = mBadgedImageView.getMeasuredWidth(); - int imageHeight = mBadgedImageView.getMeasuredHeight(); - int messageWidth = mMessageView.getMeasuredWidth(); - int messageHeight = mMessageView.getMeasuredHeight(); - mBadgedImageView.layout(left, top, left + imageWidth, top + imageHeight); - mMessageView.layout(left + imageWidth + mPadding, top, - left + imageWidth + mPadding + messageWidth, top + messageHeight); - } - /** * Populates this view with a notification. * <p> diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index c39503129454..78c4fc17c655 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -157,6 +157,15 @@ public class StackAnimationController extends return mStackPosition; } + /** Whether the stack is on the left side of the screen. */ + public boolean isStackOnLeftSide() { + if (mLayout != null) { + return mStackPosition.x - mIndividualBubbleSize / 2 < mLayout.getWidth() / 2; + } else { + return false; + } + } + /** * Flings the stack starting with the given velocities, springing it to the nearest edge * afterward. diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index dcacd0fbc644..e22b24e2ed46 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -1127,10 +1127,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } protected int getActionLayoutId(Context context) { - if (isGridEnabled(context)) { - return com.android.systemui.R.layout.global_actions_grid_item; - } - return com.android.systemui.R.layout.global_actions_item; + return com.android.systemui.R.layout.global_actions_grid_item; } public View create( @@ -1540,26 +1537,28 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, initializeLayout(); } - private boolean initializePanel() { + private boolean shouldUsePanel() { if (!isPanelEnabled(mContext) || mPanelController == null) { return false; } - View panelView = mPanelController.getPanelContent(); - if (panelView == null) { + if (mPanelController.getPanelContent() == null) { return false; } + return true; + } + + private void initializePanel() { FrameLayout panelContainer = new FrameLayout(mContext); FrameLayout.LayoutParams panelParams = new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); - panelContainer.addView(panelView, panelParams); + panelContainer.addView(mPanelController.getPanelContent(), panelParams); addContentView( panelContainer, new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - return true; } private void initializeLayout() { @@ -1578,8 +1577,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mGlobalActionsLayout.setRotationListener(this::onRotate); mGlobalActionsLayout.setAdapter(mAdapter); - boolean panelEnabled = initializePanel(); - if (!panelEnabled) { + if (!shouldUsePanel()) { if (mBackgroundDrawable == null) { mBackgroundDrawable = new GradientDrawable(mContext); } @@ -1589,12 +1587,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, com.android.systemui.R.drawable.global_action_panel_scrim); mScrimAlpha = 1f; } - mGlobalActionsLayout.setSnapToEdge(panelEnabled); + mGlobalActionsLayout.setSnapToEdge(true); getWindow().setBackgroundDrawable(mBackgroundDrawable); } private int getGlobalActionsLayoutId(Context context) { - if (isGridEnabled(context)) { + if (isForceGridEnabled(context) || shouldUsePanel()) { if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) { return com.android.systemui.R.layout.global_actions_grid_seascape; } @@ -1653,11 +1651,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, super.show(); mShowing = true; mBackgroundDrawable.setAlpha(0); - mGlobalActionsLayout.setTranslationX(getAnimTranslation()); + mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX()); + mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY()); mGlobalActionsLayout.setAlpha(0); mGlobalActionsLayout.animate() .alpha(1) .translationX(0) + .translationY(0) .setDuration(300) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) .setUpdateListener(animation -> { @@ -1675,10 +1675,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } mShowing = false; mGlobalActionsLayout.setTranslationX(0); + mGlobalActionsLayout.setTranslationY(0); mGlobalActionsLayout.setAlpha(1); mGlobalActionsLayout.animate() .alpha(0) - .translationX(getAnimTranslation()) + .translationX(mGlobalActionsLayout.getAnimationOffsetX()) + .translationY(mGlobalActionsLayout.getAnimationOffsetY()) .setDuration(300) .withEndAction(super::dismiss) .setInterpolator(new LogAccelerateInterpolator()) @@ -1701,11 +1703,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private float getAnimTranslation() { - return getContext().getResources().getDimension( - com.android.systemui.R.dimen.global_actions_panel_width) / 2; - } - @Override public void onColorsChanged(ColorExtractor extractor, int which) { if (mKeyguardShowing) { @@ -1731,17 +1728,19 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } public void onRotate(int from, int to) { - if (mShowing && isGridEnabled(mContext)) { + if (mShowing && (shouldUsePanel() || isForceGridEnabled(mContext))) { refreshDialog(); } } } /** - * Determines whether or not the Global Actions menu should use the newer grid-style layout. + * Determines whether or not the Global Actions menu should be forced to + * use the newer grid-style layout. */ - private static boolean isGridEnabled(Context context) { - return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED); + private static boolean isForceGridEnabled(Context context) { + return FeatureFlagUtils.isEnabled(context, + FeatureFlagUtils.FORCE_GLOBAL_ACTIONS_GRID_ENABLED); } /** diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java index 9a0759c70b5b..f8825690056e 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java @@ -16,6 +16,10 @@ package com.android.systemui.globalactions; +import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE; +import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE; +import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE; + import android.content.Context; import android.text.TextUtils; import android.util.AttributeSet; @@ -85,8 +89,8 @@ public class GlobalActionsGridLayout extends MultiListLayout { int rotation = RotationUtils.getRotation(mContext); boolean reverse = false; // should we add items to parents in the reverse order? - if (rotation == RotationUtils.ROTATION_NONE - || rotation == RotationUtils.ROTATION_SEASCAPE) { + if (rotation == ROTATION_NONE + || rotation == ROTATION_SEASCAPE) { reverse = !reverse; // if we're in portrait or seascape, reverse items } if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) @@ -125,9 +129,9 @@ public class GlobalActionsGridLayout extends MultiListLayout { private void updateSnapPosition() { if (mSnapToEdge) { setPadding(0, 0, 0, 0); - if (mRotation == RotationUtils.ROTATION_LANDSCAPE) { + if (mRotation == ROTATION_LANDSCAPE) { setGravity(Gravity.RIGHT); - } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) { + } else if (mRotation == ROTATION_SEASCAPE) { setGravity(Gravity.LEFT); } else { setGravity(Gravity.BOTTOM); @@ -157,9 +161,9 @@ public class GlobalActionsGridLayout extends MultiListLayout { return getSeparatedView(); } else { switch (rotation) { - case RotationUtils.ROTATION_LANDSCAPE: + case ROTATION_LANDSCAPE: return getListView().getParentView(index, false, true); - case RotationUtils.ROTATION_SEASCAPE: + case ROTATION_SEASCAPE: return getListView().getParentView(index, true, true); default: return getListView().getParentView(index, false, false); @@ -174,4 +178,31 @@ public class GlobalActionsGridLayout extends MultiListLayout { public void setDivisionView(View v) { // do nothing } + + private float getAnimationDistance() { + int rows = getListView().getRowCount(); + float gridItemSize = getContext().getResources().getDimension( + com.android.systemui.R.dimen.global_actions_grid_item_height); + return rows * gridItemSize / 2; + } + + @Override + public float getAnimationOffsetX() { + switch (RotationUtils.getRotation(getContext())) { + case ROTATION_LANDSCAPE: + return getAnimationDistance(); + case ROTATION_SEASCAPE: + return -getAnimationDistance(); + default: // Portrait + return 0; + } + } + + @Override + public float getAnimationOffsetY() { + if (RotationUtils.getRotation(mContext) == ROTATION_NONE) { + return getAnimationDistance(); + } + return 0; + } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java index 048f80196781..9c71ffc0e73b 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java @@ -109,7 +109,10 @@ public class ListGridLayout extends LinearLayout { } } - private int getRowCount() { + /** + * Get the number of rows which will be used to render children. + */ + public int getRowCount() { // special case for 3 to use a single row if (mExpectedCount == 3) { return 1; @@ -117,7 +120,10 @@ public class ListGridLayout extends LinearLayout { return (int) Math.round(Math.sqrt(mExpectedCount)); } - private int getColumnCount() { + /** + * Get the number of columns which will be used to render children. + */ + public int getColumnCount() { // special case for 3 to use a single row if (mExpectedCount == 3) { return 3; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 3140e6db2442..3ec6cb78ecc1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -795,7 +795,10 @@ public class PipTouchHandler { ? mExpandedMovementBounds : mNormalMovementBounds; try { - mPinnedStackController.setMinEdgeSize(isMenuExpanded ? mExpandedShortestEdgeSize : 0); + if (mPinnedStackController != null) { + mPinnedStackController.setMinEdgeSize( + isMenuExpanded ? mExpandedShortestEdgeSize : 0); + } } catch (RemoteException e) { Log.e(TAG, "Could not set minimized state", e); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 4f4dcbc9ce92..f69356ea14a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -41,6 +41,7 @@ import android.os.SystemClock; import android.service.notification.NotificationListenerService; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; +import android.text.TextUtils; import android.util.ArraySet; import android.view.View; import android.widget.ImageView; @@ -51,6 +52,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ContrastColorUtil; +import com.android.systemui.R; import com.android.systemui.statusbar.InflationTask; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.InflationException; @@ -393,6 +395,72 @@ public final class NotificationEntry { } /** + * Returns our best guess for the most relevant text summary of the latest update to this + * notification, based on its type. Returns null if there should not be an update message. + */ + public CharSequence getUpdateMessage(Context context) { + final Notification underlyingNotif = notification.getNotification(); + final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle(); + + try { + if (Notification.BigTextStyle.class.equals(style)) { + // Return the big text, it is big so probably important. If it's not there use the + // normal text. + CharSequence bigText = + underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT); + return !TextUtils.isEmpty(bigText) + ? bigText + : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT); + } else if (Notification.MessagingStyle.class.equals(style)) { + final List<Notification.MessagingStyle.Message> messages = + Notification.MessagingStyle.Message.getMessagesFromBundleArray( + (Parcelable[]) underlyingNotif.extras.get( + Notification.EXTRA_MESSAGES)); + + final Notification.MessagingStyle.Message latestMessage = + Notification.MessagingStyle.findLatestIncomingMessage(messages); + + if (latestMessage != null) { + final CharSequence personName = latestMessage.getSenderPerson() != null + ? latestMessage.getSenderPerson().getName() + : null; + + // Prepend the sender name if available since group chats also use messaging + // style. + if (!TextUtils.isEmpty(personName)) { + return context.getResources().getString( + R.string.notification_summary_message_format, + personName, + latestMessage.getText()); + } else { + return latestMessage.getText(); + } + } + } else if (Notification.InboxStyle.class.equals(style)) { + CharSequence[] lines = + underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES); + + // Return the last line since it should be the most recent. + if (lines != null && lines.length > 0) { + return lines[lines.length - 1]; + } + } else if (Notification.MediaStyle.class.equals(style)) { + // Return nothing, media updates aren't typically useful as a text update. + return null; + } else { + // Default to text extra. + return underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT); + } + } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) { + // No use crashing, we'll just return null and the caller will assume there's no update + // message. + e.printStackTrace(); + } + + return null; + } + + /** * Abort all existing inflation tasks */ public void abortTask() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java index 580e7024347c..2c15e87ee1e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java @@ -85,11 +85,13 @@ public class NotificationBlockingHelperManager { // - User sentiment is negative (DEBUG flag can bypass) // - The notification shade is fully expanded (guarantees we're not touching a HUN). // - The row is blockable (i.e. not non-blockable) - // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group + // - The dismissed row is a valid group (>1 or 0 children from the same channel) + // or the only child in the group if ((row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE || DEBUG) && mIsShadeExpanded && !row.getIsNonblockable() - && (!row.isChildInGroup() || row.isOnlyChildInGroup())) { + && ((!row.isChildInGroup() || row.isOnlyChildInGroup()) + && row.getNumUniqueChannels() <= 1)) { // Dismiss any current blocking helper before continuing forward (only one can be shown // at a given time). dismissCurrentBlockingHelper(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 54bdaa23ea1d..69e61201a4d0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -309,7 +309,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mDeviceProvisionedController.isDeviceProvisioned(), row.getIsNonblockable(), isForBlockingHelper, - row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE, row.getEntry().importance, row.getEntry().isHighPriority()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 2e4325b2f41f..622b869c9e4c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -39,6 +39,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Color; import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; import android.metrics.LogMaker; import android.os.Handler; import android.os.RemoteException; @@ -82,9 +83,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G public static final int ACTION_NONE = 0; static final int ACTION_UNDO = 1; + // standard controls static final int ACTION_TOGGLE_SILENT = 2; + // unused static final int ACTION_BLOCK = 3; + // blocking helper static final int ACTION_DELIVER_SILENTLY = 4; + // standard controls private static final int ACTION_ALERT = 5; private INotificationManager mINotificationManager; @@ -99,7 +104,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private NotificationChannel mSingleNotificationChannel; private int mStartingChannelImportance; private boolean mWasShownHighPriority; - private int mNotificationBlockState = ACTION_NONE; /** * The last importance level chosen by the user. Null if the user has not chosen an importance * level; non-null once the user takes an action which indicates an explicit preference. @@ -109,13 +113,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private boolean mIsNonblockable; private StatusBarNotification mSbn; private AnimatorSet mExpandAnimation; - private boolean mIsForeground; private boolean mIsDeviceProvisioned; private CheckSaveListener mCheckSaveListener; private OnSettingsClickListener mOnSettingsClickListener; private OnAppSettingsClickListener mAppSettingsClickListener; private NotificationGuts mGutsContainer; + private GradientDrawable mSelectedBackground; /** Whether this view is being shown as part of the blocking helper. */ private boolean mIsForBlockingHelper; @@ -125,40 +129,39 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G */ private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; - private OnClickListener mOnKeepShowing = v -> { - mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; - if (mIsForBlockingHelper) { - closeControls(v); - mMetricsLogger.write(getLogMaker().setCategory( - MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT)); - } - }; - + // used by standard ui private OnClickListener mOnAlert = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; mChosenImportance = IMPORTANCE_DEFAULT; - updateButtonsAndHelpText(ACTION_ALERT); + updateButtons(ACTION_ALERT); + }; + + // used by standard ui + private OnClickListener mOnSilent = v -> { + mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY; + mChosenImportance = IMPORTANCE_LOW; + updateButtons(ACTION_TOGGLE_SILENT); }; + // used by standard ui private OnClickListener mOnDismissSettings = v -> { closeControls(v); }; + // used by blocking helper + private OnClickListener mOnKeepShowing = v -> { + mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; + closeControls(v); + mMetricsLogger.write(getLogMaker().setCategory( + MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + .setType(MetricsEvent.TYPE_ACTION) + .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT)); + }; + + // used by blocking helper private OnClickListener mOnDeliverSilently = v -> { handleSaveImportance( ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT); - if (!mIsForBlockingHelper) { - updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY); - } - }; - - private OnClickListener mOnStopOrMinimizeNotifications = v -> { - handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED); - if (!mIsForBlockingHelper) { - updateButtonsAndHelpText(ACTION_BLOCK); - } }; private void handleSaveImportance(int action, int metricsSubtype) { @@ -189,6 +192,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G .setType(MetricsEvent.TYPE_DISMISS) .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO)); } else { + // TODO: this can't happen? mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS)); } saveImportanceAndExitReason(ACTION_UNDO); @@ -233,7 +237,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G bindNotification(pm, iNotificationManager, pkg, notificationChannel, numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick, onAppSettingsClick, isDeviceProvisioned, isNonblockable, - false /* isBlockingHelper */, false /* isUserSentimentNegative */, + false /* isBlockingHelper */, importance, wasShownHighPriority); } @@ -250,7 +254,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G boolean isDeviceProvisioned, boolean isNonblockable, boolean isForBlockingHelper, - boolean isUserSentimentNegative, int importance, boolean wasShownHighPriority) throws RemoteException { @@ -268,13 +271,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mStartingChannelImportance = mSingleNotificationChannel.getImportance(); mWasShownHighPriority = wasShownHighPriority; mIsNonblockable = isNonblockable; - mIsForeground = - (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; mIsForBlockingHelper = isForBlockingHelper; mAppUid = mSbn.getUid(); mDelegatePkg = mSbn.getOpPkg(); mIsDeviceProvisioned = isDeviceProvisioned; + mSelectedBackground = new GradientDrawable(); + mSelectedBackground.setShape(GradientDrawable.RECTANGLE); + mSelectedBackground.setColor(mContext.getColor(R.color.notification_guts_selection_bg)); + final float cornerRadii = getResources().getDisplayMetrics().density * 8; + mSelectedBackground.setCornerRadii(new float[]{cornerRadii, cornerRadii, cornerRadii, + cornerRadii, cornerRadii, cornerRadii, cornerRadii, cornerRadii}); + mSelectedBackground.setStroke((int) (getResources().getDisplayMetrics().density * 2), + mContext.getColor(R.color.notification_guts_selection_border)); + int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage( pkg, mAppUid, false /* includeDeleted */); if (mNumUniqueChannelsInRow == 0) { @@ -288,13 +298,74 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } bindHeader(); - bindPrompt(); - bindButtons(); + bindChannelDetails(); + + if (mIsForBlockingHelper) { + bindBlockingHelper(); + } else { + bindInlineControls(); + } mMetricsLogger.write(notificationControlsLogMaker()); } - private void bindHeader() throws RemoteException { + private void bindBlockingHelper() { + findViewById(R.id.inline_controls).setVisibility(GONE); + findViewById(R.id.blocking_helper).setVisibility(VISIBLE); + + findViewById(R.id.undo).setOnClickListener(mOnUndo); + + View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications); + turnOffButton.setOnClickListener(getSettingsOnClickListener()); + turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE); + + TextView keepShowing = findViewById(R.id.keep_showing); + keepShowing.setOnClickListener(mOnKeepShowing); + + View deliverSilently = findViewById(R.id.deliver_silently); + deliverSilently.setOnClickListener(mOnDeliverSilently); + } + + private void bindInlineControls() { + findViewById(R.id.inline_controls).setVisibility(VISIBLE); + findViewById(R.id.blocking_helper).setVisibility(GONE); + + if (mIsNonblockable) { + findViewById(R.id.non_configurable_text).setVisibility(VISIBLE); + findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE); + findViewById(R.id.interruptiveness_settings).setVisibility(GONE); + } else if (mNumUniqueChannelsInRow > 1) { + findViewById(R.id.non_configurable_text).setVisibility(GONE); + findViewById(R.id.interruptiveness_settings).setVisibility(GONE); + findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE); + } else { + findViewById(R.id.non_configurable_text).setVisibility(GONE); + findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE); + findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE); + } + + View turnOffButton = findViewById(R.id.turn_off_notifications); + turnOffButton.setOnClickListener(getSettingsOnClickListener()); + turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonblockable + ? VISIBLE : GONE); + + View done = findViewById(R.id.done); + done.setOnClickListener(mOnDismissSettings); + + + View silent = findViewById(R.id.silent_row); + View alert = findViewById(R.id.alert_row); + silent.setOnClickListener(mOnSilent); + alert.setOnClickListener(mOnAlert); + + if (mWasShownHighPriority) { + updateButtons(ACTION_ALERT); + } else { + updateButtons(ACTION_TOGGLE_SILENT); + } + } + + private void bindHeader() { // Package name Drawable pkgicon = null; ApplicationInfo info; @@ -319,31 +390,44 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G // Delegate bindDelegate(); - // Settings button. + // Set up app settings link (i.e. Customize) + View settingsLinkView = findViewById(R.id.app_settings); + Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName, + mSingleNotificationChannel, + mSbn.getId(), mSbn.getTag()); + if (settingsIntent != null + && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) { + settingsLinkView.setVisibility(VISIBLE); + settingsLinkView.setOnClickListener((View view) -> { + mAppSettingsClickListener.onClick(view, settingsIntent); + }); + } else { + settingsLinkView.setVisibility(View.GONE); + } + + // System Settings button. final View settingsButton = findViewById(R.id.info); + settingsButton.setOnClickListener(getSettingsOnClickListener()); + settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE); + } + + private OnClickListener getSettingsOnClickListener() { if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) { - settingsButton.setVisibility(View.VISIBLE); final int appUidF = mAppUid; - settingsButton.setOnClickListener( - (View view) -> { - logBlockingHelperCounter( - NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS); - mOnSettingsClickListener.onClick(view, - mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel, - appUidF); - }); - } else { - settingsButton.setVisibility(View.GONE); + return ((View view) -> { + logBlockingHelperCounter( + NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS); + mOnSettingsClickListener.onClick(view, + mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel, + appUidF); + }); } + return null; } - private void bindPrompt() throws RemoteException { - final TextView blockPrompt = findViewById(R.id.block_prompt); + private void bindChannelDetails() throws RemoteException { bindName(); bindGroup(); - if (mIsNonblockable) { - blockPrompt.setText(R.string.notification_unblockable_desc); - } } private void bindName() { @@ -450,110 +534,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - private void bindButtons() { - findViewById(R.id.undo).setOnClickListener(mOnUndo); - - boolean showInterruptivenessSettings = - !mIsNonblockable - && !mIsForeground - && !mIsForBlockingHelper - && NotificationUtils.useNewInterruptionModel(mContext); - if (showInterruptivenessSettings) { - findViewById(R.id.block_or_minimize).setVisibility(GONE); - findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE); - View done = findViewById(R.id.done_button); - done.setOnClickListener(mOnDismissSettings); - View block = findViewById(R.id.int_block_wrapper); - View silent = findViewById(R.id.int_silent_wrapper); - View alert = findViewById(R.id.int_alert_wrapper); - block.setOnClickListener(mOnStopOrMinimizeNotifications); - silent.setOnClickListener(mOnDeliverSilently); - alert.setOnClickListener(mOnAlert); - if (mNotificationBlockState != ACTION_NONE) { - updateButtonsAndHelpText(mNotificationBlockState); - } else if (mWasShownHighPriority) { - updateButtonsAndHelpText(ACTION_ALERT); - } else { - updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY); - } - } else { - findViewById(R.id.block_or_minimize).setVisibility(VISIBLE); - findViewById(R.id.interruptiveness_settings).setVisibility(GONE); - View block = findViewById(R.id.block); - TextView done = findViewById(R.id.done); - View minimize = findViewById(R.id.minimize); - View deliverSilently = findViewById(R.id.deliver_silently); - - - block.setOnClickListener(mOnStopOrMinimizeNotifications); - done.setOnClickListener(mOnKeepShowing); - minimize.setOnClickListener(mOnStopOrMinimizeNotifications); - deliverSilently.setOnClickListener(mOnDeliverSilently); - - if (mIsNonblockable) { - done.setText(android.R.string.ok); - block.setVisibility(GONE); - minimize.setVisibility(GONE); - deliverSilently.setVisibility(GONE); - } else if (mIsForeground) { - block.setVisibility(GONE); - minimize.setVisibility(VISIBLE); - } else { - block.setVisibility(VISIBLE); - minimize.setVisibility(GONE); - } - - // Set up app settings link (i.e. Customize) - View settingsLinkView = findViewById(R.id.app_settings); - Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName, - mSingleNotificationChannel, - mSbn.getId(), mSbn.getTag()); - if (!mIsForBlockingHelper - && settingsIntent != null - && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) { - settingsLinkView.setVisibility(VISIBLE); - settingsLinkView.setOnClickListener((View view) -> { - mAppSettingsClickListener.onClick(view, settingsIntent); - }); - } else { - settingsLinkView.setVisibility(View.GONE); - } - } - } - - private void updateButtonsAndHelpText(int blockState) { - mNotificationBlockState = blockState; - ImageView block = findViewById(R.id.int_block); - ImageView silent = findViewById(R.id.int_silent); - ImageView alert = findViewById(R.id.int_alert); - TextView hintText = findViewById(R.id.hint_text); + private void updateButtons(int blockState) { + View silent = findViewById(R.id.silent_row); + View alert = findViewById(R.id.alert_row); switch (blockState) { - case ACTION_BLOCK: - block.setBackgroundResource(R.drawable.circle_blue_40dp); - block.setColorFilter(Color.WHITE); - silent.setBackgroundResource(R.drawable.circle_white_40dp); - silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - alert.setBackgroundResource(R.drawable.circle_white_40dp); - alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - hintText.setText(R.string.hint_text_block); - break; - case ACTION_DELIVER_SILENTLY: - silent.setBackgroundResource(R.drawable.circle_blue_40dp); - silent.setColorFilter(Color.WHITE); - block.setBackgroundResource(R.drawable.circle_white_40dp); - block.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - alert.setBackgroundResource(R.drawable.circle_white_40dp); - alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - hintText.setText(R.string.hint_text_silent); + case ACTION_TOGGLE_SILENT: + silent.setBackground(mSelectedBackground); + alert.setBackground(null); break; case ACTION_ALERT: - alert.setBackgroundResource(R.drawable.circle_blue_40dp); - alert.setColorFilter(Color.WHITE); - block.setBackgroundResource(R.drawable.circle_white_40dp); - block.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - silent.setBackgroundResource(R.drawable.circle_white_40dp); - silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400)); - hintText.setText(R.string.hint_text_alert); + alert.setBackground(mSelectedBackground); + silent.setBackground(null); break; } } @@ -575,28 +566,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G mChosenImportance = IMPORTANCE_DEFAULT; } break; - case ACTION_BLOCK: - mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS; - if (mIsForeground) { - mChosenImportance = IMPORTANCE_MIN; - } else { - mChosenImportance = IMPORTANCE_NONE; - } - break; default: throw new IllegalArgumentException(); } } + // only used for blocking helper private void swapContent(@NotificationInfoAction int action, boolean animate) { if (mExpandAnimation != null) { mExpandAnimation.cancel(); } - View prompt = findViewById(R.id.prompt); + View blockingHelper = findViewById(R.id.blocking_helper); ViewGroup confirmation = findViewById(R.id.confirmation); TextView confirmationText = findViewById(R.id.confirmation_text); - View header = findViewById(R.id.header); saveImportanceAndExitReason(action); @@ -606,33 +589,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G case ACTION_DELIVER_SILENTLY: confirmationText.setText(R.string.notification_channel_silenced); break; - case ACTION_TOGGLE_SILENT: - if (mWasShownHighPriority) { - confirmationText.setText(R.string.notification_channel_silenced); - } else { - confirmationText.setText(R.string.notification_channel_unsilenced); - } - break; - case ACTION_BLOCK: - if (mIsForeground) { - confirmationText.setText(R.string.notification_channel_minimized); - } else { - confirmationText.setText(R.string.notification_channel_disabled); - } - break; default: throw new IllegalArgumentException(); } boolean isUndo = action == ACTION_UNDO; - prompt.setVisibility(isUndo ? VISIBLE : GONE); + blockingHelper.setVisibility(isUndo ? VISIBLE : GONE); + findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE); + findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE); confirmation.setVisibility(isUndo ? GONE : VISIBLE); - header.setVisibility(isUndo ? VISIBLE : GONE); if (animate) { - ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA, - prompt.getAlpha(), isUndo ? 1f : 0f); + ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA, + blockingHelper.getAlpha(), isUndo ? 1f : 0f); promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT); ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA, confirmation.getAlpha(), isUndo ? 0f : 1f); @@ -652,7 +622,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G @Override public void onAnimationEnd(Animator animation) { if (!mCancelled) { - prompt.setVisibility(isUndo ? VISIBLE : GONE); + blockingHelper.setVisibility(isUndo ? VISIBLE : GONE); confirmation.setVisibility(isUndo ? GONE : VISIBLE); } } @@ -674,15 +644,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; - View prompt = findViewById(R.id.prompt); - ViewGroup confirmation = findViewById(R.id.confirmation); - View header = findViewById(R.id.header); - prompt.setVisibility(VISIBLE); - prompt.setAlpha(1f); - confirmation.setVisibility(GONE); - confirmation.setAlpha(1f); - header.setVisibility(VISIBLE); - header.setAlpha(1f); + if (mIsForBlockingHelper) { + bindBlockingHelper(); + } else { + bindInlineControls(); + } mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE)); } @@ -730,8 +696,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G * commit the updated importance. * * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the - * user does not have the ability to undo the action anymore. See {@link #swapContent(boolean)} - * for where undo is handled. + * user does not have the ability to undo the action anymore. See + * {@link #swapContent(boolean, boolean)} for where undo is handled. */ @VisibleForTesting void closeControls(View v) { diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 83ec33c69629..5412cde0df55 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -71,8 +71,8 @@ local_space := $(local_empty) $(local_empty) # This appends a * to all classes and replace the space separators with commas. jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) -LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.* -LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude) +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.* +LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) ifeq ($(EXCLUDE_SYSTEMUI_TESTS),) include $(BUILD_PACKAGE) diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java new file mode 100644 index 000000000000..801308fc77da --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package com.android.systemui.bubbles; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.View; +import android.widget.TextView; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class BubbleStackViewTest extends SysuiTestCase { + private BubbleStackView mStackView; + @Mock private Bubble mBubble; + @Mock private NotificationEntry mNotifEntry; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mStackView = new BubbleStackView(mContext, new BubbleData(), null); + mBubble.entry = mNotifEntry; + } + + @Test + public void testAnimateInFlyoutForBubble() throws InterruptedException { + when(mNotifEntry.getUpdateMessage(any())).thenReturn("Test Flyout Message."); + mStackView.animateInFlyoutForBubble(mBubble); + + // Wait for the fade in. + Thread.sleep(200); + + // Flyout should be visible and showing our text. + assertEquals(1f, mStackView.findViewById(R.id.bubble_flyout).getAlpha(), .01f); + assertEquals("Test Flyout Message.", + ((TextView) mStackView.findViewById(R.id.bubble_flyout_text)).getText()); + + // Wait until it should have gone away. + Thread.sleep(BubbleStackView.FLYOUT_HIDE_AFTER + 200); + + // Flyout should be gone. + assertEquals(View.GONE, mStackView.findViewById(R.id.bubble_flyout).getVisibility()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java new file mode 100644 index 000000000000..cca9f2834e93 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package com.android.systemui.statusbar.notification.collection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; + +import android.app.Notification; +import android.os.Bundle; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NotificationEntryTest extends SysuiTestCase { + @Mock + private StatusBarNotification mStatusBarNotification; + @Mock + private Notification mNotif; + + private NotificationEntry mEntry; + private Bundle mExtras; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mStatusBarNotification.getKey()).thenReturn("key"); + when(mStatusBarNotification.getNotification()).thenReturn(mNotif); + + mExtras = new Bundle(); + mNotif.extras = mExtras; + + mEntry = new NotificationEntry(mStatusBarNotification); + } + + @Test + public void testGetUpdateMessage_default() { + final String msg = "Hello there!"; + doReturn(Notification.Style.class).when(mNotif).getNotificationStyle(); + mExtras.putCharSequence(Notification.EXTRA_TEXT, msg); + assertEquals(msg, mEntry.getUpdateMessage(mContext)); + } + + @Test + public void testGetUpdateMessage_bigText() { + final String msg = "A big hello there!"; + doReturn(Notification.BigTextStyle.class).when(mNotif).getNotificationStyle(); + mExtras.putCharSequence(Notification.EXTRA_TEXT, "A small hello there."); + mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg); + + // Should be big text, not the small text. + assertEquals(msg, mEntry.getUpdateMessage(mContext)); + } + + @Test + public void testGetUpdateMessage_media() { + doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle(); + + // Media notifs don't get update messages. + assertNull(mEntry.getUpdateMessage(mContext)); + } + + @Test + public void testGetUpdateMessage_inboxStyle() { + doReturn(Notification.InboxStyle.class).when(mNotif).getNotificationStyle(); + mExtras.putCharSequenceArray( + Notification.EXTRA_TEXT_LINES, + new CharSequence[]{ + "How do you feel about tests?", + "They're okay, I guess.", + "I hate when they're flaky.", + "Really? I prefer them that way."}); + + // Should be the last one only. + assertEquals("Really? I prefer them that way.", mEntry.getUpdateMessage(mContext)); + } + + @Test + public void testGetUpdateMessage_messagingStyle() { + doReturn(Notification.MessagingStyle.class).when(mNotif).getNotificationStyle(); + mExtras.putParcelableArray( + Notification.EXTRA_MESSAGES, + new Bundle[]{ + new Notification.MessagingStyle.Message( + "Hello", 0, "Josh").toBundle(), + new Notification.MessagingStyle.Message( + "Oh, hello!", 0, "Mady").toBundle()}); + + // Should be the last one only. + assertEquals("Mady: Oh, hello!", mEntry.getUpdateMessage(mContext)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java index 4fe364a7654b..3c91b3f1bdd3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.row; +import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE; @@ -24,11 +25,13 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.NotificationChannel; import android.content.Context; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -130,6 +133,21 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { verify(mGutsManager).openGuts(row, 0, 0, mMenuItem); } + @Test + public void testPerhapsShowBlockingHelper_notShownForMultiChannelGroup() throws Exception { + ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10); + int i = 0; + for (ExpandableNotificationRow childRow : groupRow.getNotificationChildren()) { + childRow.getEntry().channel = + new NotificationChannel(Integer.toString(i++), "", IMPORTANCE_DEFAULT); + } + + groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE; + + assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow)); + + verify(mGutsManager, never()).openGuts(groupRow, 0, 0, mMenuItem); + } @Test public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index ff849c3720f3..8380192ffd32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -325,7 +325,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false), eq(false), eq(true) /* isForBlockingHelper */, - eq(true) /* isUserSentimentNegative */, eq(0), eq(false) /* wasShownHighPriority */); } @@ -354,7 +353,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false), eq(false), eq(false) /* isForBlockingHelper */, - eq(true) /* isUserSentimentNegative */, eq(0), eq(false) /* wasShownHighPriority */); } @@ -385,7 +383,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false), eq(false), eq(true) /* isForBlockingHelper */, - eq(true) /* isUserSentimentNegative */, eq(IMPORTANCE_DEFAULT), eq(true) /* wasShownHighPriority */); } @@ -415,7 +412,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(true), eq(false), eq(false) /* isForBlockingHelper */, - eq(true) /* isUserSentimentNegative */, eq(0), eq(false) /* wasShownHighPriority */); } @@ -444,7 +440,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { eq(false), eq(false), eq(true) /* isForBlockingHelper */, - eq(true) /* isUserSentimentNegative */, eq(0), eq(false) /* wasShownHighPriority */); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index fb4fd314d363..d2f8e02311e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -313,108 +313,20 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBindNotification_BlockButton() throws Exception { + public void testBindNotification_BlockLink_BlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - final View block = mNotificationInfo.findViewById(R.id.int_block); - final View minimize = mNotificationInfo.findViewById(R.id.block_or_minimize); - assertEquals(VISIBLE, block.getVisibility()); - assertEquals(GONE, minimize.getVisibility()); - } - - @Test - public void testBindNotification_BlockButton_BlockingHelper() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT, true); - final View block = mNotificationInfo.findViewById(R.id.block); + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, mock( + NotificationInfo.OnSettingsClickListener.class), null, true, false, + true /* isBlockingHelper */, IMPORTANCE_DEFAULT, true); + final View block = + mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications); final View interruptivenessSettings = mNotificationInfo.findViewById( - R.id.interruptiveness_settings); + R.id.inline_controls); assertEquals(VISIBLE, block.getVisibility()); assertEquals(GONE, interruptivenessSettings.getVisibility()); } @Test - public void testBindNotification_SilenceButton_CurrentlyAlerting() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label); - assertEquals(VISIBLE, silent.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_silent), silent.getText()); - } - - @Test - public void testBindNotification_verifyButtonTexts() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_LOW, false); - final TextView block = mNotificationInfo.findViewById(R.id.int_block_label); - final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label); - final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label); - assertEquals(VISIBLE, silent.getVisibility()); - assertEquals(VISIBLE, block.getVisibility()); - assertEquals(VISIBLE, alert.getVisibility()); - assertEquals( - mContext.getString(R.string.inline_silent_button_silent), - silent.getText()); - assertEquals( - mContext.getString(R.string.inline_silent_button_alert), alert.getText()); - assertEquals( - mContext.getString(R.string.inline_block_button), block.getText()); - } - - @Test - public void testBindNotification_verifyHintTextForSilent() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_LOW, false); - TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); - assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText()); - } - - @Test - public void testBindNotification_verifyHintTextForBlock() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_LOW, false); - View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper); - blockWrapper.performClick(); - TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); - assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText()); - } - - @Test - public void testBindNotification_verifyHintTextForAlert() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - TextView hintText = mNotificationInfo.findViewById(R.id.hint_text); - assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText()); - } - - @Test - public void testBindNotification_MinButton() throws Exception { - mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); - final View block = mNotificationInfo.findViewById(R.id.block); - final View interruptivenessSettings = mNotificationInfo.findViewById( - R.id.interruptiveness_settings); - final View minimize = mNotificationInfo.findViewById(R.id.minimize); - assertEquals(GONE, block.getVisibility()); - assertEquals(GONE, interruptivenessSettings.getVisibility()); - assertEquals(VISIBLE, minimize.getVisibility()); - } - - @Test public void testBindNotification_SetsOnClickListenerForSettings() throws Exception { final CountDownLatch latch = new CountDownLatch(1); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, @@ -484,7 +396,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true, - true, true, + true, IMPORTANCE_DEFAULT, true); verify(mMetricsLogger).write(argThat(logMaker -> logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS @@ -499,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true, - true, true, + true, IMPORTANCE_DEFAULT, true); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1)); @@ -526,7 +438,7 @@ public class NotificationInfoTest extends SysuiTestCase { throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, IMPORTANCE_DEFAULT, true); + null, true, false, IMPORTANCE_DEFAULT, true); final TextView channelNameView = mNotificationInfo.findViewById(R.id.channel_name); assertEquals(GONE, channelNameView.getVisibility()); @@ -537,20 +449,24 @@ public class NotificationInfoTest extends SysuiTestCase { public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null, - null, true, true, IMPORTANCE_DEFAULT, true); - final TextView blockView = mNotificationInfo.findViewById(R.id.block); - assertEquals(GONE, blockView.getVisibility()); + null, true, false, IMPORTANCE_DEFAULT, true); + assertEquals(GONE, mNotificationInfo.findViewById( + R.id.interruptiveness_settings).getVisibility()); + assertEquals(VISIBLE, mNotificationInfo.findViewById( + R.id.non_configurable_multichannel_text).getVisibility()); } @Test - public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception { + public void testBindNotification_whenAppUnblockable() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, IMPORTANCE_DEFAULT, true); - final TextView view = mNotificationInfo.findViewById(R.id.block_prompt); + final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text); assertEquals(View.VISIBLE, view.getVisibility()); assertEquals(mContext.getString(R.string.notification_unblockable_desc), view.getText()); + assertEquals(GONE, + mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility()); } @Test @@ -568,23 +484,9 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block).performClick(); - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test - public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin() - throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); + IMPORTANCE_LOW, false); - mNotificationInfo.findViewById(R.id.minimize).performClick(); + mNotificationInfo.findViewById(R.id.alert_row).performClick(); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), any()); @@ -598,21 +500,7 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.int_silent).performClick(); - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test - public void testDoesNotUpdateNotificationChannelAfterImportanceChangedUnSilenced() - throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_alert).performClick(); + mNotificationInfo.findViewById(R.id.silent_row).performClick(); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), any()); @@ -650,76 +538,6 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testHandleCloseControls_setsNotificationsDisabledForMultipleChannelNotifications() - throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, - true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false - ); - - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, times(1)) - .setNotificationsEnabledWithImportanceLockForPackage( - anyString(), eq(TEST_UID), eq(false)); - } - - - @Test - public void testHandleCloseControls_keepsNotificationsEnabledForMultipleChannelNotifications() - throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, - true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false - ); - - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, times(1)) - .setNotificationsEnabledWithImportanceLockForPackage( - anyString(), eq(TEST_UID), eq(false)); - } - - @Test - public void testCloseControls_blockingHelperSavesImportanceForMultipleChannelNotifications() - throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, - 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */, - true /* provisioned */, - false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); - - NotificationGuts guts = spy(new NotificationGuts(mContext, null)); - when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); - doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean()); - doNothing().when(guts).setExposed(anyBoolean(), anyBoolean()); - guts.setGutsContent(mNotificationInfo); - mNotificationInfo.setGutsParent(guts); - - mNotificationInfo.findViewById(R.id.done).performClick(); - - verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, times(1)) - .setNotificationsEnabledWithImportanceLockForPackage( - anyString(), eq(TEST_UID), eq(true)); - } - - @Test public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper() throws Exception { NotificationInfo.CheckSaveListener listener = @@ -729,7 +547,7 @@ public class NotificationInfoTest extends SysuiTestCase { 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); + IMPORTANCE_DEFAULT, true); NotificationGuts guts = spy(new NotificationGuts(mContext, null)); when(guts.getWindowToken()).thenReturn(mock(IBinder.class)); @@ -738,7 +556,7 @@ public class NotificationInfoTest extends SysuiTestCase { guts.setGutsContent(mNotificationInfo); mNotificationInfo.setGutsParent(guts); - mNotificationInfo.findViewById(R.id.done).performClick(); + mNotificationInfo.findViewById(R.id.keep_showing).performClick(); verify(mBlockingHelperManager).dismissCurrentBlockingHelper(); mTestableLooper.processAllMessages(); @@ -757,8 +575,7 @@ public class NotificationInfoTest extends SysuiTestCase { 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, null /* onSettingsClick */, null /* onAppSettingsClick */, false /* isNonblockable */, true /* isForBlockingHelper */, - true, true /* isUserSentimentNegative */, /* isNoisy */ - IMPORTANCE_DEFAULT, true); + true, IMPORTANCE_DEFAULT, true); mNotificationInfo.handleCloseControls(true /* save */, false /* force */); @@ -777,9 +594,9 @@ public class NotificationInfoTest extends SysuiTestCase { null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); + IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.block).performClick(); + mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); mTestableLooper.processAllMessages(); verify(listener).checkSave(any(Runnable.class), eq(mSbn)); } @@ -799,7 +616,6 @@ public class NotificationInfoTest extends SysuiTestCase { false /* isNonblockable */, true /* isForBlockingHelper */, true, - false /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); NotificationGuts guts = mock(NotificationGuts.class); doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean()); @@ -811,53 +627,9 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.block).performClick(); - waitForUndoButton(); - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test - public void testBlockChangedCallsUpdateNotificationChannel_notBlockingHelper() + public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, - null, null, null, - true, false, - IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); - mNotificationInfo.handleCloseControls(true, false); - - ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); - verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture()); - assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION, - logMakerCaptor.getValue().getType()); - assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, - logMakerCaptor.getValue().getSubtype()); - - mTestableLooper.processAllMessages(); - ArgumentCaptor<NotificationChannel> updated = - ArgumentCaptor.forClass(NotificationChannel.class); - verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance()); - } - - @Test - public void testBlockChangedCallsUpdateNotificationChannel_blockingHelper() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification( mMockPackageManager, mMockINotificationManager, @@ -871,21 +643,13 @@ public class NotificationInfoTest extends SysuiTestCase { true /*provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.block).performClick(); + mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); waitForUndoButton(); mNotificationInfo.handleCloseControls(true, false); - ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); - verify(mMetricsLogger, times(3)).write(logMakerCaptor.capture()); - assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION, - logMakerCaptor.getValue().getType()); - assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, - logMakerCaptor.getValue().getSubtype()); - mTestableLooper.processAllMessages(); ArgumentCaptor<NotificationChannel> updated = ArgumentCaptor.forClass(NotificationChannel.class); @@ -893,69 +657,17 @@ public class NotificationInfoTest extends SysuiTestCase { anyString(), eq(TEST_UID), updated.capture()); assertTrue((updated.getValue().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance()); + assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); } - @Test - public void testNonBlockableAppDoesNotBecomeMin() throws Exception { + public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.minimize).performClick(); - waitForUndoButton(); - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), any()); - } - - @Test - public void testMinChangedCallsUpdateNotificationChannel() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - true, false, IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.minimize).performClick(); - waitForUndoButton(); - mNotificationInfo.handleCloseControls(true, false); - - mTestableLooper.processAllMessages(); - ArgumentCaptor<NotificationChannel> updated = - ArgumentCaptor.forClass(NotificationChannel.class); - verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( - anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance()); - } - - @Test - public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper() - throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification( - mMockPackageManager, - mMockINotificationManager, - TEST_PACKAGE_NAME, - mNotificationChannel, - 1 /* numChannels */, - mSbn, - null /* checkSaveListener */, - null /* onSettingsClick */, - null /* onAppSettingsClick */, - true /*provisioned */, - false /* isNonblockable */, - true /* isForBlockingHelper */, - true /* isUserSentimentNegative */, - IMPORTANCE_DEFAULT, - false); + IMPORTANCE_LOW, false); - mNotificationInfo.findViewById(R.id.deliver_silently).performClick(); - waitForUndoButton(); + mNotificationInfo.findViewById(R.id.keep_showing).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -963,16 +675,15 @@ public class NotificationInfoTest extends SysuiTestCase { ArgumentCaptor.forClass(NotificationChannel.class); verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), updated.capture()); - assertTrue((updated.getValue().getUserLockedFields() - & USER_LOCKED_IMPORTANCE) != 0); - assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance()); + assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE)); + assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance()); } @Test - public void testKeepUpdatesNotificationChannel() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); + public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception { + mNotificationChannel.setImportance(IMPORTANCE_DEFAULT); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, IMPORTANCE_DEFAULT, false); mNotificationInfo.handleCloseControls(true, false); @@ -983,7 +694,7 @@ public class NotificationInfoTest extends SysuiTestCase { verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( anyString(), eq(TEST_UID), updated.capture()); assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE)); - assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance()); + assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance()); } @Test @@ -993,8 +704,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.silent_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1014,8 +725,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, false); - mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.alert_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1036,8 +747,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_DEFAULT, true); - mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.silent_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1058,8 +769,8 @@ public class NotificationInfoTest extends SysuiTestCase { TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, IMPORTANCE_LOW, false); - mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.alert_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mNotificationInfo.handleCloseControls(true, false); mTestableLooper.processAllMessages(); @@ -1073,30 +784,14 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testCloseControlsDoesNotUpdateMinIfSaveIsFalse() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, false, IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.minimize).performClick(); - waitForUndoButton(); - mNotificationInfo.handleCloseControls(false, false); - - mTestableLooper.processAllMessages(); - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); - } - - @Test public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, false); + IMPORTANCE_LOW, false); - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.alert_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mNotificationInfo.handleCloseControls(false, false); mTestableLooper.processAllMessages(); @@ -1105,33 +800,17 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBlockDoesNothingIfCheckSaveListenerIsNoOp() throws Exception { - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, - (Runnable saveImportance, StatusBarNotification sbn) -> { - }, null, null, true, true, IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mTestableLooper.processAllMessages(); - mNotificationInfo.handleCloseControls(true, false); - - verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( - eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); - } - - @Test public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, (Runnable saveImportance, StatusBarNotification sbn) -> { saveImportance.run(); - }, null, null, true, false, IMPORTANCE_DEFAULT, false + }, null, null, true, false, IMPORTANCE_LOW, false ); - mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick(); - mNotificationInfo.findViewById(R.id.done_button).performClick(); + mNotificationInfo.findViewById(R.id.alert_row).performClick(); + mNotificationInfo.findViewById(R.id.done).performClick(); mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); @@ -1147,18 +826,4 @@ public class NotificationInfoTest extends SysuiTestCase { public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception { assertFalse(mNotificationInfo.willBeRemoved()); } - - @Test - public void testUndoText_min() throws Exception { - mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; - mNotificationChannel.setImportance(IMPORTANCE_LOW); - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - true, false, IMPORTANCE_DEFAULT, false); - - mNotificationInfo.findViewById(R.id.minimize).performClick(); - waitForUndoButton(); - TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text); - assertTrue(confirmationText.getText().toString().contains("minimized")); - } } diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java index a5a515f93e75..e3dc3b7a9848 100644 --- a/services/core/java/com/android/server/ServiceWatcher.java +++ b/services/core/java/com/android/server/ServiceWatcher.java @@ -382,7 +382,13 @@ public class ServiceWatcher implements ServiceConnection { /** * Runs the given function synchronously if currently connected, and returns the default value * if not currently connected or if any exception is thrown. + * + * @deprecated Using this function is an indication that your AIDL API is broken. Calls from + * system server to outside MUST be one-way, and so cannot return any result, and this + * method should not be needed or used. Use a separate callback interface to allow outside + * components to return results back to the system server. */ + @Deprecated public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) { try { return runOnHandlerBlocking(() -> { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 4598d3ef7f4b..307919223a2b 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -929,13 +929,20 @@ class StorageManagerService extends IStorageManager.Stub private void initIfBootedAndConnected() { Slog.d(TAG, "Thinking about init, mBootCompleted=" + mBootCompleted + ", mDaemonConnected=" + mDaemonConnected); - if (mBootCompleted && mDaemonConnected - && !StorageManager.isFileEncryptedNativeOnly()) { - // When booting a device without native support, make sure that our - // user directories are locked or unlocked based on the current - // emulation status. - final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly(); - Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked); + if (mBootCompleted && mDaemonConnected) { + // Tell vold to lock or unlock the user directories based on the + // current file-based encryption status. + final boolean initLocked; + if (StorageManager.isFileEncryptedNativeOrEmulated()) { + // For native FBE this is a no-op after reboot, but this is + // still needed in case of framework restarts. + Slog.d(TAG, "FBE is enabled; ensuring all user directories are locked."); + initLocked = true; + } else { + // This is in case FBE emulation was turned off. + Slog.d(TAG, "FBE is disabled; ensuring the FBE emulation state is cleared."); + initLocked = false; + } final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); for (UserInfo user : users) { try { @@ -3840,7 +3847,9 @@ class StorageManagerService extends IStorageManager.Stub uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE); final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0, uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE); - final boolean hasStorage = hasRead || hasWrite; + // STOPSHIP: remove this temporary hack once we have dynamic runtime + // permissions fully enabled again + final boolean hasStorage = hasRead || hasWrite || true; // We're only willing to give out broad access if they also hold // runtime permission; this is a firm CDD requirement diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index e42666c6a637..7ab70fad70d4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -49,6 +49,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false; + static final boolean DEBUG_COMPACTION = DEBUG_ALL || false; static final boolean DEBUG_LRU = DEBUG_ALL || false; static final boolean DEBUG_MU = DEBUG_ALL || false; static final boolean DEBUG_NETWORK = DEBUG_ALL || false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index a5932ccc1a5c..1757c9816355 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -213,6 +213,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal.CheckPermissionDelegate; +import android.content.pm.PackageParser; import android.content.pm.ParceledListSlice; import android.content.pm.PathPermission; import android.content.pm.PermissionInfo; @@ -18474,7 +18475,9 @@ public class ActivityManagerService extends IActivityManager.Stub void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) { final boolean updateFrameworkRes = packagesToUpdate.contains("android"); - + if (updateFrameworkRes) { + PackageParser.readConfigUseRoundIcon(null); + } mProcessList.updateApplicationInfoLocked(packagesToUpdate, userId, updateFrameworkRes); if (updateFrameworkRes) { diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 8a462dabd14c..d1379b669563 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityTaskManager.RESIZE_MODE_USER; @@ -427,8 +428,12 @@ final class ActivityManagerShellCommand extends ShellCommand { if (intent.getComponent() != null) { packageName = intent.getComponent().getPackageName(); } else { + // queryIntentActivities does not convert user id, so we convert it here first + int userIdForQuery = mInternal.mUserController.handleIncomingUser( + Binder.getCallingPid(), Binder.getCallingUid(), mUserId, false, + ALLOW_NON_FULL, "ActivityManagerShellCommand", null); List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0, - mUserId).getList(); + userIdForQuery).getList(); if (activities == null || activities.size() <= 0) { getErrPrintWriter().println("Error: Intent does not match any activities: " + intent); diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index ac1002689dc0..043dc8d00081 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -18,6 +18,9 @@ package com.android.server.am; import static android.os.Process.THREAD_PRIORITY_FOREGROUND; +import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; + import android.app.ActivityManager; import android.app.ActivityThread; import android.os.Debug; @@ -30,6 +33,7 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.OnPropertyChangedListener; import android.text.TextUtils; import android.util.EventLog; +import android.util.Slog; import android.util.StatsLog; import com.android.internal.annotations.GuardedBy; @@ -39,7 +43,12 @@ import com.android.server.ServiceThread; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.Random; +import java.util.Set; public final class AppCompactor { @@ -55,6 +64,12 @@ public final class AppCompactor { @VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6"; @VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; + @VisibleForTesting static final String KEY_COMPACT_FULL_RSS_THROTTLE_KB = + "compact_full_rss_throttle_kb"; + @VisibleForTesting static final String KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = + "compact_full_delta_rss_throttle_kb"; + @VisibleForTesting static final String KEY_COMPACT_PROC_STATE_THROTTLE = + "compact_proc_state_throttle"; // Phenotype sends int configurations and we map them to the strings we'll use on device, // preventing a weird string value entering the kernel. @@ -79,6 +94,11 @@ public final class AppCompactor { @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000; // The sampling rate to push app compaction events into statsd for upload. @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f; + @VisibleForTesting static final long DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB = 12_000L; + @VisibleForTesting static final long DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = 8_000L; + // Format of this string should be a comma separated list of integers. + @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE = + String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER); @VisibleForTesting interface PropertyChangedCallbackForTest { @@ -123,6 +143,12 @@ public final class AppCompactor { updateCompactionThrottles(); } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { updateStatsdSampleRate(); + } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) { + updateFullRssThrottle(); + } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) { + updateFullDeltaRssThrottle(); + } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) { + updateProcStateThrottle(); } } if (mTestCallback != null) { @@ -154,18 +180,42 @@ public final class AppCompactor { @VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6; @GuardedBy("mPhenotypeFlagLock") private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; - private final Random mRandom = new Random(); @GuardedBy("mPhenotypeFlagLock") @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile long mFullAnonRssThrottleKb = + DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB; + @GuardedBy("mPhenoypeFlagLock") + @VisibleForTesting volatile long mFullDeltaRssThrottleKb = + DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB; + @GuardedBy("mPhenoypeFlagLock") + @VisibleForTesting final Set<Integer> mProcStateThrottle; // Handler on which compaction runs. private Handler mCompactionHandler; + // Maps process ID to last compaction statistics for processes that we've fully compacted. Used + // when evaluating throttles that we only consider for "full" compaction, so we don't store + // data for "some" compactions. + private Map<Integer, LastCompactionStats> mLastCompactionStats = + new LinkedHashMap<Integer, LastCompactionStats>() { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > 100; + } + }; + + private int mSomeCompactionCount; + private int mFullCompactionCount; + private int mPersistentCompactionCount; + private int mBfgsCompactionCount; + public AppCompactor(ActivityManagerService am) { mAm = am; mCompactionThread = new ServiceThread("CompactionThread", THREAD_PRIORITY_FOREGROUND, true); + mProcStateThrottle = new HashSet<>(); } @VisibleForTesting @@ -186,10 +236,12 @@ public final class AppCompactor { updateCompactionActions(); updateCompactionThrottles(); updateStatsdSampleRate(); + updateFullRssThrottle(); + updateFullDeltaRssThrottle(); + updateProcStateThrottle(); } Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(), Process.THREAD_GROUP_SYSTEM); - } /** @@ -212,7 +264,33 @@ public final class AppCompactor { pw.println(" " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull); pw.println(" " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome); pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull); + pw.println(" " + KEY_COMPACT_THROTTLE_5 + "=" + mCompactThrottleBFGS); + pw.println(" " + KEY_COMPACT_THROTTLE_6 + "=" + mCompactThrottlePersistent); pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate); + pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "=" + + mFullAnonRssThrottleKb); + pw.println(" " + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + "=" + + mFullDeltaRssThrottleKb); + pw.println(" " + KEY_COMPACT_PROC_STATE_THROTTLE + "=" + + Arrays.toString(mProcStateThrottle.toArray(new Integer[0]))); + + pw.println(" " + mSomeCompactionCount + " some, " + mFullCompactionCount + + " full, " + mPersistentCompactionCount + " persistent, " + + mBfgsCompactionCount + " BFGS compactions."); + + if (mLastCompactionStats != null) { + pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size() + + " processes."); + if (DEBUG_COMPACTION) { + for (Map.Entry<Integer, LastCompactionStats> entry + : mLastCompactionStats.entrySet()) { + int pid = entry.getKey(); + LastCompactionStats stats = entry.getValue(); + pw.println(" " + pid + ": " + + Arrays.toString(stats.getRssAfterCompaction())); + } + } + } } } @@ -277,7 +355,7 @@ public final class AppCompactor { /** * Reads the flag value from DeviceConfig to determine whether app compaction - * should be enabled, and starts/stops the compaction thread as needed. + * should be enabled, and starts the compaction thread if needed. */ @GuardedBy("mPhenotypeFlagLock") private void updateUseCompaction() { @@ -360,6 +438,58 @@ public final class AppCompactor { mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate)); } + @GuardedBy("mPhenotypeFlagLock") + private void updateFullRssThrottle() { + mFullAnonRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_FULL_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); + + // Don't allow negative values. 0 means don't apply the throttle. + if (mFullAnonRssThrottleKb < 0) { + mFullAnonRssThrottleKb = DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB; + } + } + + @GuardedBy("mPhenotypeFlagLock") + private void updateFullDeltaRssThrottle() { + mFullDeltaRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); + + if (mFullDeltaRssThrottleKb < 0) { + mFullDeltaRssThrottleKb = DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB; + } + } + + @GuardedBy("mPhenotypeFlagLock") + private void updateProcStateThrottle() { + String procStateThrottleString = DeviceConfig.getString( + DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_PROC_STATE_THROTTLE, + DEFAULT_COMPACT_PROC_STATE_THROTTLE); + if (!parseProcStateThrottle(procStateThrottleString)) { + Slog.w(TAG_AM, "Unable to parse app compact proc state throttle \"" + + procStateThrottleString + "\" falling back to default."); + if (!parseProcStateThrottle(DEFAULT_COMPACT_PROC_STATE_THROTTLE)) { + Slog.wtf(TAG_AM, + "Unable to parse default app compact proc state throttle " + + DEFAULT_COMPACT_PROC_STATE_THROTTLE); + } + } + } + + private boolean parseProcStateThrottle(String procStateThrottleString) { + String[] procStates = TextUtils.split(procStateThrottleString, ","); + mProcStateThrottle.clear(); + for (String procState : procStates) { + try { + mProcStateThrottle.add(Integer.parseInt(procState)); + } catch (NumberFormatException e) { + Slog.e(TAG_AM, "Failed to parse default app compaction proc state: " + + procState); + return false; + } + } + return true; + } + @VisibleForTesting static String compactActionIntToString(int action) { switch(action) { @@ -376,6 +506,22 @@ public final class AppCompactor { } } + @VisibleForTesting static String procStateListToString(Integer... processStates) { + return Arrays.toString(processStates); + } + + private static final class LastCompactionStats { + private final long[] mRssAfterCompaction; + + LastCompactionStats(long[] rss) { + mRssAfterCompaction = rss; + } + + long[] getRssAfterCompaction() { + return mRssAfterCompaction; + } + } + private final class MemCompactionHandler extends Handler { private MemCompactionHandler() { super(mCompactionThread.getLooper()); @@ -392,24 +538,34 @@ public final class AppCompactor { final String name; int pendingAction, lastCompactAction; long lastCompactTime; + LastCompactionStats lastCompactionStats; + int lastOomAdj = msg.arg1; + int procState = msg.arg2; synchronized (mAm) { proc = mPendingCompactionProcesses.remove(0); pendingAction = proc.reqCompactAction; + pid = proc.pid; + name = proc.processName; // don't compact if the process has returned to perceptible // and this is only a cached/home/prev compaction if ((pendingAction == COMPACT_PROCESS_SOME || pendingAction == COMPACT_PROCESS_FULL) && (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, + "Skipping compaction as process " + name + " is " + + "now perceptible."); + } return; } - pid = proc.pid; - name = proc.processName; - lastCompactAction = proc.lastCompactAction; lastCompactTime = proc.lastCompactTime; + // remove rather than get so that insertion order will be updated when we + // put the post-compaction stats back into the map. + lastCompactionStats = mLastCompactionStats.remove(pid); } if (pid == 0) { @@ -431,6 +587,12 @@ public final class AppCompactor { || (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < mCompactThrottleSomeFull))) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping some compaction for " + name + + ": too soon. throttle=" + mCompactThrottleSomeSome + + "/" + mCompactThrottleSomeFull + " last=" + + (start - lastCompactTime) + "ms ago"); + } return; } } else if (pendingAction == COMPACT_PROCESS_FULL) { @@ -439,18 +601,35 @@ public final class AppCompactor { || (lastCompactAction == COMPACT_PROCESS_FULL && (start - lastCompactTime < mCompactThrottleFullFull))) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping full compaction for " + name + + ": too soon. throttle=" + mCompactThrottleFullSome + + "/" + mCompactThrottleFullFull + " last=" + + (start - lastCompactTime) + "ms ago"); + } return; } } else if (pendingAction == COMPACT_PROCESS_PERSISTENT) { if (start - lastCompactTime < mCompactThrottlePersistent) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping persistent compaction for " + name + + ": too soon. throttle=" + mCompactThrottlePersistent + + " last=" + (start - lastCompactTime) + "ms ago"); + } return; } } else if (pendingAction == COMPACT_PROCESS_BFGS) { if (start - lastCompactTime < mCompactThrottleBFGS) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping bfgs compaction for " + name + + ": too soon. throttle=" + mCompactThrottleBFGS + + " last=" + (start - lastCompactTime) + "ms ago"); + } return; } } } + switch (pendingAction) { case COMPACT_PROCESS_SOME: action = mCompactActionSome; @@ -470,12 +649,77 @@ public final class AppCompactor { return; } + if (mProcStateThrottle.contains(procState)) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping full compaction for process " + name + + "; proc state is " + procState); + } + return; + } + + long[] rssBefore = Process.getRss(pid); + long anonRssBefore = rssBefore[2]; + + if (rssBefore[0] == 0 && rssBefore[1] == 0 && rssBefore[2] == 0 + && rssBefore[3] == 0) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping compaction for" + "process " + pid + + " with no memory usage. Dead?"); + } + return; + } + + if (action.equals(COMPACT_ACTION_FULL) || action.equals(COMPACT_ACTION_ANON)) { + if (mFullAnonRssThrottleKb > 0L + && anonRssBefore < mFullAnonRssThrottleKb) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping full compaction for process " + + name + "; anon RSS is too small: " + anonRssBefore + + "KB."); + } + return; + } + + if (lastCompactionStats != null && mFullDeltaRssThrottleKb > 0L) { + long[] lastRss = lastCompactionStats.getRssAfterCompaction(); + long absDelta = Math.abs(rssBefore[1] - lastRss[1]) + + Math.abs(rssBefore[2] - lastRss[2]) + + Math.abs(rssBefore[3] - lastRss[3]); + if (absDelta <= mFullDeltaRssThrottleKb) { + if (DEBUG_COMPACTION) { + Slog.d(TAG_AM, "Skipping full compaction for process " + + name + "; abs delta is too small: " + absDelta + + "KB."); + } + return; + } + } + } + + // Now we've passed through all the throttles and are going to compact, update + // bookkeeping. + switch (pendingAction) { + case COMPACT_PROCESS_SOME: + mSomeCompactionCount++; + break; + case COMPACT_PROCESS_FULL: + mFullCompactionCount++; + break; + case COMPACT_PROCESS_PERSISTENT: + mPersistentCompactionCount++; + break; + case COMPACT_PROCESS_BFGS: + mBfgsCompactionCount++; + break; + default: + break; + } + try { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact " + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full") + ": " + name); long zramFreeKbBefore = Debug.getZramFreeKb(); - long[] rssBefore = Process.getRss(pid); FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim"); fos.write(action.getBytes()); fos.close(); @@ -487,8 +731,9 @@ public final class AppCompactor { rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0] - rssBefore[0], rssAfter[1] - rssBefore[1], rssAfter[2] - rssBefore[2], rssAfter[3] - rssBefore[3], time, - lastCompactAction, lastCompactTime, msg.arg1, msg.arg2, + lastCompactAction, lastCompactTime, lastOomAdj, procState, zramFreeKbBefore, zramFreeKbAfter - zramFreeKbBefore); + // Note that as above not taking mPhenoTypeFlagLock here to avoid locking // on every single compaction for a flag that will seldom change and the // impact of reading the wrong value here is low. @@ -496,17 +741,23 @@ public final class AppCompactor { StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction, rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, - lastCompactAction, lastCompactTime, msg.arg1, - ActivityManager.processStateAmToProto(msg.arg2), + lastCompactAction, lastCompactTime, lastOomAdj, + ActivityManager.processStateAmToProto(procState), zramFreeKbBefore, zramFreeKbAfter); } + synchronized (mAm) { proc.lastCompactTime = end; proc.lastCompactAction = pendingAction; } - Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); + + if (action.equals(COMPACT_ACTION_FULL) + || action.equals(COMPACT_ACTION_ANON)) { + mLastCompactionStats.put(pid, new LastCompactionStats(rssAfter)); + } } catch (Exception e) { // nothing to do, presumably the process died + } finally { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 1681c5bc61d3..bc78d1ad751f 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -19,6 +19,7 @@ package com.android.server.attention; import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE; import static android.provider.Settings.System.ADAPTIVE_SLEEP; import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED; +import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN; import android.Manifest; import android.annotation.NonNull; @@ -249,6 +250,7 @@ public class AttentionManagerService extends SystemService { if (userState.mPendingAttentionCheck != null && userState.mPendingAttentionCheck.mCallbackInternal.equals( callbackInternal)) { + userState.mPendingAttentionCheck.cancel(ATTENTION_FAILURE_UNKNOWN); userState.mPendingAttentionCheck = null; } return; @@ -624,7 +626,7 @@ public class AttentionManagerService extends SystemService { if (userState == null) { return; } - cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN); + cancel(userState, ATTENTION_FAILURE_UNKNOWN); mContext.unbindService(userState.mConnection); userState.mConnection.cleanupService(); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java index 0bbaf25aaa12..53076975849b 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java @@ -90,7 +90,11 @@ public class AnnouncementAggregator extends ICloseHandle.Stub { for (ModuleWatcher watcher : mModuleWatchers) { combined.addAll(watcher.currentList); } - TunerCallback.dispatch(() -> mListener.onListUpdated(combined)); + try { + mListener.onListUpdated(combined); + } catch (RemoteException ex) { + Slog.e(TAG, "mListener.onListUpdated() failed: ", ex); + } } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java index 2df89821611c..5e79c5943d7b 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java @@ -54,13 +54,6 @@ public class BroadcastRadioService { @GuardedBy("mLock") private final Map<Integer, RadioModule> mModules = new HashMap<>(); - // Map from module ID to TunerSession created by openSession(). - // - // Because this service currently implements a 1 AIDL to 1 HAL policy, mTunerSessions is used to - // enforce the "aggresive open" policy mandated for IBroadcastRadio.openSession(). In the - // future, this solution will be replaced with a multiple-AIDL to 1 HAL implementation. - private final Map<Integer, TunerSession> mTunerSessions = new HashMap<>(); - private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() { @Override public void onRegistration(String fqName, String serviceName, boolean preexisting) { @@ -81,8 +74,10 @@ public class BroadcastRadioService { } Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName + " (HAL 2.0)"); - closeTunerSessionLocked(moduleId); - mModules.put(moduleId, module); + RadioModule prevModule = mModules.put(moduleId, module); + if (prevModule != null) { + prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); + } if (newService) { mServiceNameToModuleIdMap.put(serviceName, moduleId); @@ -105,8 +100,10 @@ public class BroadcastRadioService { Slog.v(TAG, "serviceDied(" + cookie + ")"); synchronized (mLock) { int moduleId = (int) cookie; - mModules.remove(moduleId); - closeTunerSessionLocked(moduleId); + RadioModule prevModule = mModules.remove(moduleId); + if (prevModule != null) { + prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); + } for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) { if (entry.getValue() == moduleId) { @@ -166,13 +163,9 @@ public class BroadcastRadioService { if (module == null) { throw new IllegalArgumentException("Invalid module ID"); } - closeTunerSessionLocked(moduleId); } TunerSession tunerSession = module.openSession(callback); - synchronized (mLock) { - mTunerSessions.put(moduleId, tunerSession); - } if (legacyConfig != null) { tunerSession.setConfiguration(legacyConfig); } @@ -198,12 +191,4 @@ public class BroadcastRadioService { } return aggregator; } - - private void closeTunerSessionLocked(int moduleId) { - TunerSession tunerSession = mTunerSessions.remove(moduleId); - if (tunerSession != null) { - Slog.d(TAG, "Closing previous TunerSession"); - tunerSession.close(RadioTuner.ERROR_HARDWARE_FAILURE); - } - } } diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index 832f8e1c9205..acb0207ff11f 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -26,16 +26,26 @@ import android.hardware.broadcastradio.V2_0.DabTableEntry; import android.hardware.broadcastradio.V2_0.IAnnouncementListener; import android.hardware.broadcastradio.V2_0.IBroadcastRadio; import android.hardware.broadcastradio.V2_0.ICloseHandle; +import android.hardware.broadcastradio.V2_0.ITunerCallback; import android.hardware.broadcastradio.V2_0.ITunerSession; +import android.hardware.broadcastradio.V2_0.ProgramInfo; +import android.hardware.broadcastradio.V2_0.ProgramListChunk; +import android.hardware.broadcastradio.V2_0.ProgramSelector; import android.hardware.broadcastradio.V2_0.Result; +import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.RadioManager; +import android.os.DeadObjectException; import android.os.RemoteException; import android.util.MutableInt; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; + import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.stream.Collectors; class RadioModule { @@ -44,8 +54,63 @@ class RadioModule { @NonNull private final IBroadcastRadio mService; @NonNull public final RadioManager.ModuleProperties mProperties; + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private ITunerSession mHalTunerSession; + + // Tracks antenna state reported by HAL (if any). + @GuardedBy("mLock") + private Boolean mAntennaConnected = null; + + @GuardedBy("mLock") + private RadioManager.ProgramInfo mProgramInfo = null; + + // Callback registered with the HAL to relay callbacks to AIDL clients. + private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() { + @Override + public void onTuneFailed(int result, ProgramSelector programSelector) { + fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal( + programSelector))); + } + + @Override + public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) { + RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo); + synchronized (mLock) { + mProgramInfo = programInfo; + fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo)); + } + } + + @Override + public void onProgramListUpdated(ProgramListChunk programListChunk) { + // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan + // back out to clients. + fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal( + programListChunk))); + } + + @Override + public void onAntennaStateChange(boolean connected) { + synchronized (mLock) { + mAntennaConnected = connected; + fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); + } + } + + @Override + public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { + fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); + } + }; + + // Collection of active AIDL tuner sessions created through openSession(). + @GuardedBy("mLock") + private final Set<TunerSession> mAidlTunerSessions = new HashSet<>(); + private RadioModule(@NonNull IBroadcastRadio service, - @NonNull RadioManager.ModuleProperties properties) { + @NonNull RadioManager.ModuleProperties properties) throws RemoteException { mProperties = Objects.requireNonNull(properties); mService = Objects.requireNonNull(service); } @@ -81,21 +146,85 @@ class RadioModule { public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) throws RemoteException { - TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb)); - Mutable<ITunerSession> hwSession = new Mutable<>(); - MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); + synchronized (mLock) { + if (mHalTunerSession == null) { + Mutable<ITunerSession> hwSession = new Mutable<>(); + mService.openSession(mHalTunerCallback, (result, session) -> { + Convert.throwOnError("openSession", result); + hwSession.value = session; + }); + mHalTunerSession = Objects.requireNonNull(hwSession.value); + } + TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb); + mAidlTunerSessions.add(tunerSession); - synchronized (mService) { - mService.openSession(cb, (result, session) -> { - hwSession.value = session; - halResult.value = result; - }); + // Propagate state to new client. Note: These callbacks are invoked while holding mLock + // to prevent race conditions with new callbacks from the HAL. + if (mAntennaConnected != null) { + userCb.onAntennaState(mAntennaConnected); + } + if (mProgramInfo != null) { + userCb.onCurrentProgramInfoChanged(mProgramInfo); + } + + return tunerSession; + } + } + + public void closeSessions(Integer error) { + // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close() + // must be called without mAidlTunerSessions locked because it can call + // onTunerSessionClosed(). + TunerSession[] tunerSessions; + synchronized (mLock) { + tunerSessions = new TunerSession[mAidlTunerSessions.size()]; + mAidlTunerSessions.toArray(tunerSessions); + mAidlTunerSessions.clear(); + } + for (TunerSession tunerSession : tunerSessions) { + tunerSession.close(error); + } + } + + void onTunerSessionClosed(TunerSession tunerSession) { + synchronized (mLock) { + mAidlTunerSessions.remove(tunerSession); + if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) { + Slog.v(TAG, "closing HAL tuner session"); + try { + mHalTunerSession.close(); + } catch (RemoteException ex) { + Slog.e(TAG, "mHalTunerSession.close() failed: ", ex); + } + mHalTunerSession = null; + } } + } - Convert.throwOnError("openSession", halResult.value); - Objects.requireNonNull(hwSession.value); + interface AidlCallbackRunnable { + void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; + } - return new TunerSession(this, hwSession.value, cb); + // Invokes runnable with each TunerSession currently open. + void fanoutAidlCallback(AidlCallbackRunnable runnable) { + synchronized (mLock) { + fanoutAidlCallbackLocked(runnable); + } + } + + private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { + for (TunerSession tunerSession : mAidlTunerSessions) { + try { + runnable.run(tunerSession.mCallback); + } catch (DeadObjectException ex) { + // The other side died without calling close(), so just purge it from our + // records. + Slog.e(TAG, "Removing dead TunerSession"); + mAidlTunerSessions.remove(tunerSession); + } catch (RemoteException ex) { + Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex); + } + } } public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes, diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java deleted file mode 100644 index 3c4b49c91cf2..000000000000 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java +++ /dev/null @@ -1,76 +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.broadcastradio.hal2; - -import android.annotation.NonNull; -import android.hardware.broadcastradio.V2_0.ITunerCallback; -import android.hardware.broadcastradio.V2_0.ProgramInfo; -import android.hardware.broadcastradio.V2_0.ProgramListChunk; -import android.hardware.broadcastradio.V2_0.ProgramSelector; -import android.hardware.broadcastradio.V2_0.VendorKeyValue; -import android.os.RemoteException; -import android.util.Slog; - -import java.util.ArrayList; -import java.util.Objects; - -class TunerCallback extends ITunerCallback.Stub { - private static final String TAG = "BcRadio2Srv.cb"; - - final android.hardware.radio.ITunerCallback mClientCb; - - interface RunnableThrowingRemoteException { - void run() throws RemoteException; - } - - TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) { - mClientCb = Objects.requireNonNull(clientCallback); - } - - static void dispatch(RunnableThrowingRemoteException func) { - try { - func.run(); - } catch (RemoteException ex) { - Slog.e(TAG, "callback call failed", ex); - } - } - - @Override - public void onTuneFailed(int result, ProgramSelector selector) { - dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector))); - } - - @Override - public void onCurrentProgramInfoChanged(ProgramInfo info) { - dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info))); - } - - @Override - public void onProgramListUpdated(ProgramListChunk chunk) { - dispatch(() -> mClientCb.onProgramListUpdated(Convert.programListChunkFromHal(chunk))); - } - - @Override - public void onAntennaStateChange(boolean connected) { - dispatch(() -> mClientCb.onAntennaState(connected)); - } - - @Override - public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { - dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); - } -} diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java index 05ca144ed3b9..008fea5831ad 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -43,7 +43,7 @@ class TunerSession extends ITuner.Stub { private final RadioModule mModule; private final ITunerSession mHwSession; - private final TunerCallback mCallback; + final android.hardware.radio.ITunerCallback mCallback; private boolean mIsClosed = false; private boolean mIsMuted = false; @@ -51,7 +51,7 @@ class TunerSession extends ITuner.Stub { private RadioManager.BandConfig mDummyConfig = null; TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession, - @NonNull TunerCallback callback) { + @NonNull android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); mCallback = Objects.requireNonNull(callback); @@ -73,9 +73,14 @@ class TunerSession extends ITuner.Stub { synchronized (mLock) { if (mIsClosed) return; if (error != null) { - TunerCallback.dispatch(() -> mCallback.mClientCb.onError(error)); + try { + mCallback.onError(error); + } catch (RemoteException ex) { + Slog.w(TAG, "mCallback.onError() failed: ", ex); + } } mIsClosed = true; + mModule.onTunerSessionClosed(this); } } @@ -96,7 +101,7 @@ class TunerSession extends ITuner.Stub { checkNotClosedLocked(); mDummyConfig = Objects.requireNonNull(config); Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x"); - TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config)); + mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config)); } } @@ -174,7 +179,7 @@ class TunerSession extends ITuner.Stub { @Override public boolean startBackgroundScan() { Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x"); - TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete()); + mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete()); return true; } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 2a91b4f5eef0..cec4d693ad32 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -1846,6 +1846,7 @@ public class InputManagerService extends IInputManager.Stub // Native callback. private void onPointerDownOutsideFocus(IBinder touchedToken) { + mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken); } // Native callback. @@ -2060,6 +2061,14 @@ public class InputManagerService extends IInputManager.Stub public int getPointerLayer(); public int getPointerDisplayId(); + + /** + * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event + * occurred on a window that did not have focus. + * + * @param touchedToken The token for the window that received the input event. + */ + void onPointerDownOutsideFocus(IBinder touchedToken); } /** diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f24a3b46950d..e62714e7b5fe 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -476,6 +476,7 @@ public class PackageManagerService extends IPackageManager.Stub static final int SCAN_AS_VENDOR = 1 << 20; static final int SCAN_AS_PRODUCT = 1 << 21; static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22; + static final int SCAN_AS_ODM = 1 << 23; @IntDef(flag = true, prefix = { "SCAN_" }, value = { SCAN_NO_DEX, @@ -594,6 +595,8 @@ public class PackageManagerService extends IPackageManager.Stub private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay"; + private static final String ODM_OVERLAY_DIR = "/odm/overlay"; + /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -2523,6 +2526,13 @@ public class PackageManagerService extends IPackageManager.Stub | SCAN_AS_SYSTEM | SCAN_AS_PRODUCT_SERVICES, 0); + scanDirTracedLI(new File(ODM_OVERLAY_DIR), + mDefParseFlags + | PackageParser.PARSE_IS_SYSTEM_DIR, + scanFlags + | SCAN_AS_SYSTEM + | SCAN_AS_ODM, + 0); mParallelPackageParserCallback.findStaticOverlayPackages(); @@ -3226,6 +3236,8 @@ public class PackageManagerService extends IPackageManager.Stub // once we have a booted system. mInstaller.setWarnIfHeld(mPackages); + PackageParser.readConfigUseRoundIcon(mContext.getResources()); + mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -10399,6 +10411,7 @@ public class PackageManagerService extends IPackageManager.Stub * <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li> * <li>{@link #SCAN_AS_INSTANT_APP}</li> * <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li> + * <li>{@link #SCAN_AS_ODM}</li> * </ul> */ private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags, @@ -10435,6 +10448,10 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) { scanFlags |= SCAN_AS_PRODUCT_SERVICES; } + if ((systemPkgSetting.pkgPrivateFlags + & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) { + scanFlags |= SCAN_AS_ODM; + } } if (pkgSetting != null) { final int userId = ((user == null) ? 0 : user.getIdentifier()); @@ -11206,6 +11223,10 @@ public class PackageManagerService extends IPackageManager.Stub pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; } + if ((scanFlags & SCAN_AS_ODM) != 0) { + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM; + } + // Check if the package is signed with the same key as the platform package. if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) || (platformPkg != null && compareSignatures( @@ -11532,17 +11553,44 @@ public class PackageManagerService extends IPackageManager.Stub " is static but not pre-installed."); } - // The only case where we allow installation of a non-system overlay is when - // its signature is signed with the platform certificate. - PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); - if ((platformPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.mSigningDetails.signatures) - != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " + pkg.packageName + - " must be signed with the platform certificate."); + // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be + // signed with the platform certificate. Check this in increasing order of + // computational cost. + if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) { + final PackageSetting platformPkgSetting = + mSettings.getPackageLPr("android"); + if ((platformPkgSetting.signatures.mSigningDetails + != PackageParser.SigningDetails.UNKNOWN) + && (compareSignatures( + platformPkgSetting.signatures.mSigningDetails.signatures, + pkg.mSigningDetails.signatures) + != PackageManager.SIGNATURE_MATCH)) { + throw new PackageManagerException("Overlay " + pkg.packageName + + " must target Q or later, " + + "or be signed with the platform certificate"); + } + } + + // A non-preloaded overlay package, without <overlay android:targetName>, will + // only be used if it is signed with the same certificate as its target. If the + // target is already installed, check this here to augment the last line of + // defence which is OMS. + if (pkg.mOverlayTargetName == null) { + final PackageSetting targetPkgSetting = + mSettings.getPackageLPr(pkg.mOverlayTarget); + if (targetPkgSetting != null) { + if ((targetPkgSetting.signatures.mSigningDetails + != PackageParser.SigningDetails.UNKNOWN) + && (compareSignatures( + targetPkgSetting.signatures.mSigningDetails.signatures, + pkg.mSigningDetails.signatures) + != PackageManager.SIGNATURE_MATCH)) { + throw new PackageManagerException("Overlay " + pkg.packageName + + " and target " + pkg.mOverlayTarget + " signed with" + + " different certificates, and the overlay lacks" + + " <overlay android:targetName>"); + } + } } } } @@ -12128,6 +12176,8 @@ public class PackageManagerService extends IPackageManager.Stub codeRoot = Environment.getProductDirectory(); } else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) { codeRoot = Environment.getProductServicesDirectory(); + } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) { + codeRoot = Environment.getOdmDirectory(); } else { // Unrecognized code path; take its top real segment as the apk root: // e.g. /something/app/blah.apk => /something @@ -17215,13 +17265,15 @@ public class PackageManagerService extends IPackageManager.Stub final boolean oem = isOemApp(oldPackage); final boolean vendor = isVendorApp(oldPackage); final boolean product = isProductApp(oldPackage); + final boolean odm = isOdmApp(oldPackage); final @ParseFlags int systemParseFlags = parseFlags; final @ScanFlags int systemScanFlags = scanFlags | SCAN_AS_SYSTEM | (privileged ? SCAN_AS_PRIVILEGED : 0) | (oem ? SCAN_AS_OEM : 0) | (vendor ? SCAN_AS_VENDOR : 0) - | (product ? SCAN_AS_PRODUCT : 0); + | (product ? SCAN_AS_PRODUCT : 0) + | (odm ? SCAN_AS_ODM : 0); if (DEBUG_INSTALL) { Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg @@ -17552,6 +17604,10 @@ public class PackageManagerService extends IPackageManager.Stub & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; } + private static boolean isOdmApp(PackageParser.Package pkg) { + return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + private static boolean hasDomainURLs(PackageParser.Package pkg) { return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0; } @@ -18326,6 +18382,15 @@ public class PackageManagerService extends IPackageManager.Stub return false; } + static boolean locationIsOdm(String path) { + try { + return path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/"); + } catch (IOException e) { + Slog.e(TAG, "Unable to access code path " + path); + } + return false; + } + /* * Tries to delete system package. */ @@ -18439,6 +18504,9 @@ public class PackageManagerService extends IPackageManager.Stub if (locationIsProductServices(codePathString)) { scanFlags |= SCAN_AS_PRODUCT_SERVICES; } + if (locationIsOdm(codePathString)) { + scanFlags |= SCAN_AS_ODM; + } final File codePath = new File(codePathString); final PackageParser.Package pkg = @@ -20841,6 +20909,7 @@ public class PackageManagerService extends IPackageManager.Stub mContext.getContentResolver(), android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1; PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled); + if (DEBUG_SETTINGS) { Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled); } diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index 2c2cc7ea78f9..ead09b424d61 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -152,6 +152,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0; } + public boolean isOdm() { + return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0; + } + public boolean isSystem() { return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java index fbf54391209c..a24818f04f52 100644 --- a/services/core/java/com/android/server/pm/SettingBase.java +++ b/services/core/java/com/android/server/pm/SettingBase.java @@ -64,6 +64,7 @@ abstract class SettingBase { | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES - | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER); + | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER + | ApplicationInfo.PRIVATE_FLAG_ODM); } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index f0f9f723b64a..4f81fd9f7a9f 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -777,7 +777,8 @@ public final class Settings { | ApplicationInfo.PRIVATE_FLAG_OEM | ApplicationInfo.PRIVATE_FLAG_VENDOR | ApplicationInfo.PRIVATE_FLAG_PRODUCT - | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES); + | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES + | ApplicationInfo.PRIVATE_FLAG_ODM); pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; @@ -789,6 +790,8 @@ public final class Settings { pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT; pkgSetting.pkgPrivateFlags |= pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES; + pkgSetting.pkgPrivateFlags |= + pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM; pkgSetting.primaryCpuAbiString = primaryCpuAbi; pkgSetting.secondaryCpuAbiString = secondaryCpuAbi; if (childPkgNames != null) { @@ -4420,6 +4423,7 @@ public final class Settings { ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT", ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES", ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD", + ApplicationInfo.PRIVATE_FLAG_ODM, "ODM", }; void dumpVersionLPr(IndentingPrintWriter pw) { diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index f46835eb51fc..6b500967f429 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -6,6 +6,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS; import android.os.Debug; import android.os.IBinder; @@ -232,6 +233,11 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal } } + @Override + public void onPointerDownOutsideFocus(IBinder touchedToken) { + mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget(); + } + /** Waits until the built-in input devices have been configured. */ public boolean waitForInputDevicesReady(long timeoutMillis) { synchronized (mInputDevicesReadyMonitor) { diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index f85fdb6c3882..d3dba90fe4e6 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -63,6 +63,7 @@ final class InputMonitor { // When true, need to call updateInputWindowsLw(). private boolean mUpdateInputWindowsNeeded = true; private boolean mUpdateInputWindowsPending; + private boolean mApplyImmediately; // Currently focused input window handle. private InputWindowHandle mFocusedInputWindowHandle; @@ -152,7 +153,7 @@ final class InputMonitor { mService = service; mDisplayContent = mService.mRoot.getDisplayContent(displayId); mDisplayId = displayId; - mInputTransaction = mDisplayContent.getPendingTransaction(); + mInputTransaction = mService.mTransactionFactory.make(); mHandler = AnimationThread.getHandler(); mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer(); } @@ -319,6 +320,14 @@ final class InputMonitor { } } + void updateInputWindowsImmediately() { + if (mUpdateInputWindowsPending) { + mApplyImmediately = true; + mUpdateInputWindows.run(); + mApplyImmediately = false; + } + } + /* Called when the current input focus changes. * Layer assignment is assumed to be complete by the time this is called. */ @@ -433,7 +442,12 @@ final class InputMonitor { wallpaperInputConsumer.show(mInputTransaction, 0); } - mDisplayContent.scheduleAnimation(); + if (mApplyImmediately) { + mInputTransaction.apply(); + } else { + mDisplayContent.getPendingTransaction().merge(mInputTransaction); + mDisplayContent.scheduleAnimation(); + } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index f1560d961209..144efb49e84a 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -17,8 +17,6 @@ package com.android.server.wm; import static android.app.ActivityManager.START_TASK_TO_FRONT; -import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE; -import static android.app.AppOpsManager.OP_NONE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -34,25 +32,16 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_T import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS; import android.app.ActivityOptions; -import android.app.AppOpsManager; import android.app.IAssistDataReceiver; import android.content.ComponentName; -import android.content.Context; import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; import android.os.RemoteException; import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; -import com.android.server.LocalServices; -import com.android.server.am.AssistDataRequester; -import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; -import java.util.List; - /** * Manages the recents animation, including the reordering of the stacks for the transition and * cleanup. See {@link com.android.server.wm.RecentsAnimationController}. @@ -70,7 +59,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks, private final int mCallingPid; private int mTargetActivityType; - private AssistDataRequester mAssistDataRequester; // The stack to restore the target stack behind when the animation is finished private ActivityStack mRestoreTargetBehindStack; @@ -135,9 +123,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mWindowManager.deferSurfaceLayout(); try { - // Kick off the assist data request in the background before showing the target activity - requestAssistData(recentsComponent, recentsUid, assistDataReceiver); - if (hasExistingActivity) { // Move the recents activity into place for the animation if it is not top most mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack); @@ -216,78 +201,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks, } } - /** - * Requests assist data for the top visible activities. - */ - private void requestAssistData(ComponentName recentsComponent, int recentsUid, - @Deprecated IAssistDataReceiver assistDataReceiver) { - final AppOpsManager appOpsManager = (AppOpsManager) - mService.mContext.getSystemService(Context.APP_OPS_SERVICE); - final List<IBinder> topActivities = - mService.mRootActivityContainer.getTopVisibleActivities(); - final AssistDataRequester.AssistDataRequesterCallbacks assistDataCallbacks; - if (assistDataReceiver != null) { - assistDataCallbacks = new AssistDataReceiverProxy(assistDataReceiver, - recentsComponent.getPackageName()) { - @Override - public void onAssistDataReceivedLocked(Bundle data, int activityIndex, - int activityCount) { - // Try to notify the intelligence service first - final ContentCaptureManagerInternal imService = - LocalServices.getService(ContentCaptureManagerInternal.class); - final IBinder activityToken = topActivities.get(activityIndex); - final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); - if (r != null && (imService == null - || !imService.sendActivityAssistData(r.mUserId, activityToken, data))) { - // Otherwise, use the provided assist data receiver - super.onAssistDataReceivedLocked(data, activityIndex, activityCount); - } - } - }; - } else { - final ContentCaptureManagerInternal imService = - LocalServices.getService(ContentCaptureManagerInternal.class); - if (imService == null) { - // There is no intelligence service, so there is no point requesting assist data - return; - } - - assistDataCallbacks = new AssistDataRequester.AssistDataRequesterCallbacks() { - @Override - public boolean canHandleReceivedAssistDataLocked() { - return true; - } - - @Override - public void onAssistDataReceivedLocked(Bundle data, int activityIndex, - int activityCount) { - // Try to notify the intelligence service - final IBinder activityToken = topActivities.get(activityIndex); - final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken); - if (r != null) { - imService.sendActivityAssistData(r.mUserId, activityToken, data); - } - } - }; - } - mAssistDataRequester = new AssistDataRequester(mService.mContext, mWindowManager, - appOpsManager, assistDataCallbacks, this, OP_ASSIST_STRUCTURE, OP_NONE); - mAssistDataRequester.requestAutofillData(topActivities, - recentsUid, recentsComponent.getPackageName()); - } - private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { synchronized (mService.mGlobalLock) { if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller=" + mWindowManager.getRecentsAnimationController() + " reorderMode=" + reorderMode); - // Cancel the associated assistant data request - if (mAssistDataRequester != null) { - mAssistDataRequester.cancel(); - mAssistDataRequester = null; - } - // Unregister for stack order changes mDefaultDisplay.unregisterStackOrderChangedListener(this); diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index 4ff552ec3c91..79baab6bfbb6 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -22,12 +22,9 @@ import static android.view.PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; -import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; - import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; -import android.os.Handler; import android.view.MotionEvent; import android.view.WindowManagerPolicyConstants.PointerEventListener; @@ -40,67 +37,15 @@ import com.android.server.wm.WindowManagerService.H; public class TaskTapPointerEventListener implements PointerEventListener { private final Region mTouchExcludeRegion = new Region(); - private final Region mTmpRegion = new Region(); private final WindowManagerService mService; private final DisplayContent mDisplayContent; - private final Handler mHandler; - private final Runnable mMoveDisplayToTop; private final Rect mTmpRect = new Rect(); private int mPointerIconType = TYPE_NOT_SPECIFIED; - private int mLastDownX; - private int mLastDownY; public TaskTapPointerEventListener(WindowManagerService service, DisplayContent displayContent) { mService = service; mDisplayContent = displayContent; - mHandler = new Handler(mService.mH.getLooper()); - mMoveDisplayToTop = () -> { - int x; - int y; - synchronized (this) { - x = mLastDownX; - y = mLastDownY; - } - synchronized (mService.mGlobalLock) { - if (!mService.mPerDisplayFocusEnabled - && mService.mRoot.getTopFocusedDisplayContent() != mDisplayContent - && inputMethodWindowContains(x, y)) { - // In a single focus system, if the input method window and the input method - // target window are on the different displays, when the user is tapping on the - // input method window, we don't move its display to top. Otherwise, the input - // method target window will lose the focus. - return; - } - final Region windowTapExcludeRegion = Region.obtain(); - mDisplayContent.amendWindowTapExcludeRegion(windowTapExcludeRegion); - if (windowTapExcludeRegion.contains(x, y)) { - windowTapExcludeRegion.recycle(); - // The user is tapping on the window tap exclude region. We don't move this - // display to top. A window tap exclude region, for example, may be set by an - // ActivityView, and the region would match the bounds of both the ActivityView - // and the virtual display in it. In this case, we would take the tap that is on - // the embedded virtual display instead of this display. - return; - } - windowTapExcludeRegion.recycle(); - WindowContainer parent = mDisplayContent.getParent(); - if (parent != null && parent.getTopChild() != mDisplayContent) { - parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent, - true /* includingParents */); - // For compatibility, only the topmost activity is allowed to be resumed for - // pre-Q app. Ensure the topmost activities are resumed whenever a display is - // moved to top. - // TODO(b/123761773): Investigate whether we can move this into - // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is - // risky to do so because it seems possible to resume activities as part of a - // larger transaction and it's too early to resume based on current order - // when performing updateTopResumedActivityIfNeeded(). - mDisplayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */, - 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */); - } - } - }; } @Override @@ -115,9 +60,6 @@ public class TaskTapPointerEventListener implements PointerEventListener { mService.mTaskPositioningController.handleTapOutsideTask( mDisplayContent, x, y); } - mLastDownX = x; - mLastDownY = y; - mHandler.post(mMoveDisplayToTop); } } break; @@ -178,17 +120,4 @@ public class TaskTapPointerEventListener implements PointerEventListener { mTouchExcludeRegion.set(newRegion); } } - - private int getDisplayId() { - return mDisplayContent.getDisplayId(); - } - - private boolean inputMethodWindowContains(int x, int y) { - final WindowState inputMethodWindow = mDisplayContent.mInputMethodWindow; - if (inputMethodWindow == null || !inputMethodWindow.isVisibleLw()) { - return false; - } - inputMethodWindow.getTouchableRegion(mTmpRegion); - return mTmpRegion.contains(x, y); - } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 20d02ee5355e..8dfb02efb526 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -73,6 +73,7 @@ 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.ActivityStackSupervisor.PRESERVE_WINDOWS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT; @@ -4519,6 +4520,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int SET_RUNNING_REMOTE_ANIMATION = 59; public static final int ANIMATION_FAILSAFE = 60; public static final int RECOMPUTE_FOCUS = 61; + public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62; /** * Used to denote that an integer field in a message will not be used. @@ -4910,6 +4912,13 @@ public class WindowManagerService extends IWindowManager.Stub } break; } + case ON_POINTER_DOWN_OUTSIDE_FOCUS: { + synchronized (mGlobalLock) { + final IBinder touchedToken = (IBinder) msg.obj; + onPointerDownOutsideFocusLocked(touchedToken); + } + break; + } } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); @@ -7522,22 +7531,24 @@ public class WindowManagerService extends IWindowManager.Stub @Override public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) { - boolean shouldWaitForAnimComplete = false; + boolean shouldWaitForAnimToComplete = false; if (ev instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent) ev; - shouldWaitForAnimComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE + shouldWaitForAnimToComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE || keyEvent.getAction() == KeyEvent.ACTION_DOWN; } else if (ev instanceof MotionEvent) { MotionEvent motionEvent = (MotionEvent) ev; - shouldWaitForAnimComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE + shouldWaitForAnimToComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE || motionEvent.getAction() == MotionEvent.ACTION_DOWN; } - if (shouldWaitForAnimComplete) { + if (shouldWaitForAnimToComplete) { waitForAnimationsToComplete(); synchronized (mGlobalLock) { mWindowPlacerLocked.performSurfacePlacementIfScheduled(); + mRoot.forAllDisplays(displayContent -> + displayContent.getInputMonitor().updateInputWindowsImmediately()); } new SurfaceControl.Transaction().syncInputWindows().apply(true); @@ -7569,4 +7580,37 @@ public class WindowManagerService extends IWindowManager.Stub mGlobalLock.notifyAll(); } } + + private void onPointerDownOutsideFocusLocked(IBinder touchedToken) { + final WindowState touchedWindow = windowForClientLocked(null, touchedToken, false); + if (touchedWindow == null) { + return; + } + + final DisplayContent displayContent = touchedWindow.getDisplayContent(); + if (displayContent == null) { + return; + } + + if (!touchedWindow.canReceiveKeys()) { + // If the window that received the input event cannot receive keys, don't move the + // display it's on to the top since that window won't be able to get focus anyway. + return; + } + + final WindowContainer parent = displayContent.getParent(); + if (parent != null && parent.getTopChild() != displayContent) { + parent.positionChildAt(WindowContainer.POSITION_TOP, displayContent, + true /* includingParents */); + // For compatibility, only the topmost activity is allowed to be resumed for pre-Q + // app. Ensure the topmost activities are resumed whenever a display is moved to top. + // TODO(b/123761773): Investigate whether we can move this into + // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is risky + // to do so because it seems possible to resume activities as part of a larger + // transaction and it's too early to resume based on current order when performing + // updateTopResumedActivityIfNeeded(). + displayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */, + 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */); + } + } } diff --git a/services/net/Android.bp b/services/net/Android.bp index 8f48f5b3d292..f73a285c1a94 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -59,6 +59,7 @@ java_library_static { srcs: ["java/**/*.java"], static_libs: [ "dnsresolver_aidl_interface-java", + "ipmemorystore-client", "netd_aidl_interface-java", "networkstack-aidl-interfaces-java", ] diff --git a/services/net/java/android/net/IIpMemoryStore.aidl b/services/net/java/android/net/IIpMemoryStore.aidl index 6f88dec8dee9..63feae65756f 100644 --- a/services/net/java/android/net/IIpMemoryStore.aidl +++ b/services/net/java/android/net/IIpMemoryStore.aidl @@ -20,8 +20,8 @@ import android.net.ipmemorystore.Blob; import android.net.ipmemorystore.NetworkAttributesParcelable; import android.net.ipmemorystore.IOnBlobRetrievedListener; import android.net.ipmemorystore.IOnL2KeyResponseListener; -import android.net.ipmemorystore.IOnNetworkAttributesRetrieved; -import android.net.ipmemorystore.IOnSameNetworkResponseListener; +import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.IOnSameL3NetworkResponseListener; import android.net.ipmemorystore.IOnStatusListener; /** {@hide} */ @@ -84,7 +84,7 @@ oneway interface IIpMemoryStore { * @param listener The listener that will be invoked to return the answer. * @return (through the listener) A SameL3NetworkResponse containing the answer and confidence. */ - void isSameNetwork(String l2Key1, String l2Key2, IOnSameNetworkResponseListener listener); + void isSameNetwork(String l2Key1, String l2Key2, IOnSameL3NetworkResponseListener listener); /** * Retrieve the network attributes for a key. @@ -95,7 +95,7 @@ oneway interface IIpMemoryStore { * @return (through the listener) The network attributes and the L2 key associated with * the query. */ - void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrieved listener); + void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrievedListener listener); /** * Retrieve previously stored private data. diff --git a/services/net/java/android/net/IpMemoryStoreClient.java b/services/net/java/android/net/IpMemoryStoreClient.java index 2f4fdbd8a4a7..379c017b2990 100644 --- a/services/net/java/android/net/IpMemoryStoreClient.java +++ b/services/net/java/android/net/IpMemoryStoreClient.java @@ -20,14 +20,13 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.ipmemorystore.Blob; -import android.net.ipmemorystore.IOnBlobRetrievedListener; -import android.net.ipmemorystore.IOnL2KeyResponseListener; -import android.net.ipmemorystore.IOnNetworkAttributesRetrieved; -import android.net.ipmemorystore.IOnSameNetworkResponseListener; -import android.net.ipmemorystore.IOnStatusListener; import android.net.ipmemorystore.NetworkAttributes; +import android.net.ipmemorystore.OnBlobRetrievedListener; +import android.net.ipmemorystore.OnL2KeyResponseListener; +import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener; +import android.net.ipmemorystore.OnSameL3NetworkResponseListener; +import android.net.ipmemorystore.OnStatusListener; import android.net.ipmemorystore.Status; -import android.net.ipmemorystore.StatusParcelable; import android.os.RemoteException; import android.util.Log; @@ -50,12 +49,6 @@ public abstract class IpMemoryStoreClient { @NonNull protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException; - protected StatusParcelable internalErrorStatus() { - final StatusParcelable error = new StatusParcelable(); - error.resultCode = Status.ERROR_UNKNOWN; - return error; - } - /** * Store network attributes for a given L2 key. * If L2Key is null, choose automatically from the attributes ; passing null is equivalent to @@ -74,12 +67,13 @@ public abstract class IpMemoryStoreClient { */ public void storeNetworkAttributes(@NonNull final String l2Key, @NonNull final NetworkAttributes attributes, - @Nullable final IOnStatusListener listener) { + @Nullable final OnStatusListener listener) { try { try { - getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener); + getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), + OnStatusListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onComplete(internalErrorStatus()); + listener.onComplete(new Status(Status.ERROR_UNKNOWN)); } } catch (RemoteException e) { Log.e(TAG, "Error storing network attributes", e); @@ -99,12 +93,13 @@ public abstract class IpMemoryStoreClient { */ public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId, @NonNull final String name, @NonNull final Blob data, - @Nullable final IOnStatusListener listener) { + @Nullable final OnStatusListener listener) { try { try { - getService().storeBlob(l2Key, clientId, name, data, listener); + getService().storeBlob(l2Key, clientId, name, data, + OnStatusListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onComplete(internalErrorStatus()); + listener.onComplete(new Status(Status.ERROR_UNKNOWN)); } } catch (RemoteException e) { Log.e(TAG, "Error storing blob", e); @@ -126,12 +121,13 @@ public abstract class IpMemoryStoreClient { * Through the listener, returns the L2 key if one matched, or null. */ public void findL2Key(@NonNull final NetworkAttributes attributes, - @NonNull final IOnL2KeyResponseListener listener) { + @NonNull final OnL2KeyResponseListener listener) { try { try { - getService().findL2Key(attributes.toParcelable(), listener); + getService().findL2Key(attributes.toParcelable(), + OnL2KeyResponseListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onL2KeyResponse(internalErrorStatus(), null); + listener.onL2KeyResponse(new Status(Status.ERROR_UNKNOWN), null); } } catch (RemoteException e) { Log.e(TAG, "Error finding L2 Key", e); @@ -148,12 +144,13 @@ public abstract class IpMemoryStoreClient { * Through the listener, a SameL3NetworkResponse containing the answer and confidence. */ public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2, - @NonNull final IOnSameNetworkResponseListener listener) { + @NonNull final OnSameL3NetworkResponseListener listener) { try { try { - getService().isSameNetwork(l2Key1, l2Key2, listener); + getService().isSameNetwork(l2Key1, l2Key2, + OnSameL3NetworkResponseListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onSameNetworkResponse(internalErrorStatus(), null); + listener.onSameL3NetworkResponse(new Status(Status.ERROR_UNKNOWN), null); } } catch (RemoteException e) { Log.e(TAG, "Error checking for network sameness", e); @@ -170,12 +167,13 @@ public abstract class IpMemoryStoreClient { * the query. */ public void retrieveNetworkAttributes(@NonNull final String l2Key, - @NonNull final IOnNetworkAttributesRetrieved listener) { + @NonNull final OnNetworkAttributesRetrievedListener listener) { try { try { - getService().retrieveNetworkAttributes(l2Key, listener); + getService().retrieveNetworkAttributes(l2Key, + OnNetworkAttributesRetrievedListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null); + listener.onNetworkAttributesRetrieved(new Status(Status.ERROR_UNKNOWN), null, null); } } catch (RemoteException e) { Log.e(TAG, "Error retrieving network attributes", e); @@ -194,12 +192,13 @@ public abstract class IpMemoryStoreClient { * and the name of the data associated with the query. */ public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId, - @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) { + @NonNull final String name, @NonNull final OnBlobRetrievedListener listener) { try { try { - getService().retrieveBlob(l2Key, clientId, name, listener); + getService().retrieveBlob(l2Key, clientId, name, + OnBlobRetrievedListener.toAIDL(listener)); } catch (InterruptedException | ExecutionException m) { - listener.onBlobRetrieved(internalErrorStatus(), null, null, null); + listener.onBlobRetrieved(new Status(Status.ERROR_UNKNOWN), null, null, null); } } catch (RemoteException e) { Log.e(TAG, "Error retrieving blob", e); diff --git a/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl index fb4ca3b97895..870e217eb5b7 100644 --- a/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl +++ b/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl @@ -20,7 +20,7 @@ import android.net.ipmemorystore.NetworkAttributesParcelable; import android.net.ipmemorystore.StatusParcelable; /** {@hide} */ -oneway interface IOnNetworkAttributesRetrieved { +oneway interface IOnNetworkAttributesRetrievedListener { /** * Network attributes were fetched for the specified L2 key. While the L2 key will never * be null, the attributes may be if no data is stored about this L2 key. diff --git a/services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/services/net/java/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl index 294bd3bd4012..b8ccfb99fddd 100644 --- a/services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl +++ b/services/net/java/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl @@ -20,10 +20,10 @@ import android.net.ipmemorystore.SameL3NetworkResponseParcelable; import android.net.ipmemorystore.StatusParcelable; /** {@hide} */ -oneway interface IOnSameNetworkResponseListener { +oneway interface IOnSameL3NetworkResponseListener { /** * The memory store has come up with the answer to a query that was sent. */ - void onSameNetworkResponse(in StatusParcelable status, + void onSameL3NetworkResponse(in StatusParcelable status, in SameL3NetworkResponseParcelable response); } diff --git a/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java b/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java new file mode 100644 index 000000000000..9685ff6dd3ca --- /dev/null +++ b/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return a blob. + * @hide + */ +public interface OnBlobRetrievedListener { + /** + * The memory store has come up with the answer to a query that was sent. + */ + void onBlobRetrieved(Status status, String l2Key, String name, Blob blob); + + /** Converts this OnBlobRetrievedListener to a parcelable object */ + @NonNull + static IOnBlobRetrievedListener toAIDL(final OnBlobRetrievedListener listener) { + return new IOnBlobRetrievedListener.Stub() { + @Override + public void onBlobRetrieved(final StatusParcelable statusParcelable, final String l2Key, + final String name, final Blob blob) { + listener.onBlobRetrieved(new Status(statusParcelable), l2Key, name, blob); + } + }; + } +} diff --git a/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java b/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java new file mode 100644 index 000000000000..80209c574203 --- /dev/null +++ b/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return a L2 key. + * @hide + */ +public interface OnL2KeyResponseListener { + /** + * The operation has completed with the specified status. + */ + void onL2KeyResponse(Status status, String l2Key); + + /** Converts this OnL2KeyResponseListener to a parcelable object */ + @NonNull + static IOnL2KeyResponseListener toAIDL(final OnL2KeyResponseListener listener) { + return new IOnL2KeyResponseListener.Stub() { + @Override + public void onL2KeyResponse(final StatusParcelable statusParcelable, + final String l2Key) { + listener.onL2KeyResponse(new Status(statusParcelable), l2Key); + } + }; + } +} diff --git a/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java b/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java new file mode 100644 index 000000000000..f0f6f4016139 --- /dev/null +++ b/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return network attributes. + * @hide + */ +public interface OnNetworkAttributesRetrievedListener { + /** + * The memory store has come up with the answer to a query that was sent. + */ + void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attributes); + + /** Converts this OnNetworkAttributesRetrievedListener to a parcelable object */ + @NonNull + static IOnNetworkAttributesRetrievedListener toAIDL( + final OnNetworkAttributesRetrievedListener listener) { + return new IOnNetworkAttributesRetrievedListener.Stub() { + @Override + public void onNetworkAttributesRetrieved(final StatusParcelable statusParcelable, + final String l2Key, + final NetworkAttributesParcelable networkAttributesParcelable) { + listener.onNetworkAttributesRetrieved( + new Status(statusParcelable), l2Key, + new NetworkAttributes(networkAttributesParcelable)); + } + }; + } +} diff --git a/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java b/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java new file mode 100644 index 000000000000..ba1e0e6f2b9f --- /dev/null +++ b/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java @@ -0,0 +1,44 @@ +/* + * 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. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return a response about network sameness. + * @hide + */ +public interface OnSameL3NetworkResponseListener { + /** + * The memory store has come up with the answer to a query that was sent. + */ + void onSameL3NetworkResponse(Status status, SameL3NetworkResponse response); + + /** Converts this OnSameL3NetworkResponseListener to a parcelable object */ + @NonNull + static IOnSameL3NetworkResponseListener toAIDL(final OnSameL3NetworkResponseListener listener) { + return new IOnSameL3NetworkResponseListener.Stub() { + @Override + public void onSameL3NetworkResponse(final StatusParcelable statusParcelable, + final SameL3NetworkResponseParcelable sameL3NetworkResponseParcelable) { + listener.onSameL3NetworkResponse( + new Status(statusParcelable), + new SameL3NetworkResponse(sameL3NetworkResponseParcelable)); + } + }; + } +} diff --git a/services/net/java/android/net/ipmemorystore/OnStatusListener.java b/services/net/java/android/net/ipmemorystore/OnStatusListener.java new file mode 100644 index 000000000000..0de16660ff5f --- /dev/null +++ b/services/net/java/android/net/ipmemorystore/OnStatusListener.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +package android.net.ipmemorystore; + +import android.annotation.NonNull; + +/** + * A listener for the IpMemoryStore to return a status to a client. + * @hide + */ +public interface OnStatusListener { + /** + * The operation has completed with the specified status. + */ + void onComplete(Status status); + + /** Converts this OnStatusListener to a parcelable object */ + @NonNull + static IOnStatusListener toAIDL(final OnStatusListener listener) { + return new IOnStatusListener.Stub() { + @Override + public void onComplete(final StatusParcelable statusParcelable) { + listener.onComplete(new Status(statusParcelable)); + } + }; + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java index b0c97d1b4f48..475901a75d0d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java @@ -25,6 +25,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; +import android.text.TextUtils; import com.android.server.appop.AppOpsService; import com.android.server.testables.TestableDeviceConfig; @@ -38,6 +39,8 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.io.File; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -103,6 +106,22 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_4); assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo( AppCompactor.DEFAULT_STATSD_SAMPLE_RATE); + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); + assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); + + Set<Integer> expected = new HashSet<>(); + for (String s : TextUtils.split(AppCompactor.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) { + expected.add(Integer.parseInt(s)); + } + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); } @Test @@ -139,6 +158,14 @@ public final class AppCompactorTest { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE, Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, + Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, + Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false); // Then calling init will read and set that flag. mCompactorUnderTest.init(); @@ -157,12 +184,19 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1); assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1); assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo( AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f); assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1); assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1); + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactly(1, 2, 3); } @Test @@ -321,6 +355,10 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_3); assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); // Repeat for each of the throttle keys. mCountDown = new CountDownLatch(1); @@ -335,6 +373,10 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_3); assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -348,6 +390,10 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_3); assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, @@ -361,13 +407,51 @@ public final class AppCompactorTest { AppCompactor.DEFAULT_COMPACT_THROTTLE_3); assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_THROTTLE_5, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_1); + assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_2); + assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_3); + assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_THROTTLE_6, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_1); + assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_2); + assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_3); + assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_4); + assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_5); + assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo( + AppCompactor.DEFAULT_COMPACT_THROTTLE_6); } @Test public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException { mCompactorUnderTest.init(); - // When we override mStatsdSampleRate with a reasonable values ... + // When we override mStatsdSampleRate with a reasonable value ... mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE, @@ -380,11 +464,11 @@ public final class AppCompactorTest { } @Test - public void statsdSanokeRate_listensToDeviceConfigChangesBadValues() + public void statsdSampleRate_listensToDeviceConfigChangesBadValues() throws InterruptedException { mCompactorUnderTest.init(); - // When we override mStatsdSampleRate with a reasonable values ... + // When we override mStatsdSampleRate with an unreasonable value ... mCountDown = new CountDownLatch(1); DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false); @@ -396,7 +480,7 @@ public final class AppCompactorTest { } @Test - public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues() + public void statsdSampleRate_listensToDeviceConfigChangesOutOfRangeValues() throws InterruptedException { mCompactorUnderTest.init(); @@ -420,6 +504,147 @@ public final class AppCompactorTest { assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(1.0f); } + @Test + public void fullCompactionRssThrottleKb_listensToDeviceConfigChanges() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with a reasonable value ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, + Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1); + } + + @Test + public void fullCompactionRssThrottleKb_listensToDeviceConfigChangesBadValues() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with an unreasonable value ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "-100", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB); + } + + @Test + public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChanges() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with a reasonable value ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, + Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1); + } + + @Test + public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChangesBadValues() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with an unreasonable value ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "-100", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo( + AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB); + } + + @Test + public void procStateThrottle_listensToDeviceConfigChanges() + throws InterruptedException { + mCompactorUnderTest.init(); + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactly(1, 2, 3); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).isEmpty(); + } + + @Test + public void procStateThrottle_listensToDeviceConfigChangesBadValues() + throws InterruptedException { + mCompactorUnderTest.init(); + + Set<Integer> expected = new HashSet<>(); + for (String s : TextUtils.split(AppCompactor.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) { + expected.add(Integer.parseInt(s)); + } + + // Not numbers + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); + + // Empty splits + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, ",", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, ",,3", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, + AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,,3", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue(); + assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected); + } + private class TestInjector extends Injector { @Override public AppOpsService getAppOpsService(File file, Handler handler) { diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java index 465c2b1be3d9..2cb369d28029 100644 --- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java +++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java @@ -78,7 +78,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { * * @hide */ - public final boolean isUsingCarrierAggregation; + public boolean mIsUsingCarrierAggregation; /** * @hide @@ -92,7 +92,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { this.isNrAvailable = isNrAvailable; this.isEnDcAvailable = isEnDcAvailable; this.mLteVopsSupportInfo = lteVops; - this.isUsingCarrierAggregation = isUsingCarrierAggregation; + this.mIsUsingCarrierAggregation = isUsingCarrierAggregation; } private DataSpecificRegistrationInfo(Parcel source) { @@ -101,7 +101,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { isNrAvailable = source.readBoolean(); isEnDcAvailable = source.readBoolean(); mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source); - isUsingCarrierAggregation = source.readBoolean(); + mIsUsingCarrierAggregation = source.readBoolean(); } @Override @@ -111,7 +111,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { dest.writeBoolean(isNrAvailable); dest.writeBoolean(isEnDcAvailable); mLteVopsSupportInfo.writeToParcel(dest, flags); - dest.writeBoolean(isUsingCarrierAggregation); + dest.writeBoolean(mIsUsingCarrierAggregation); } @Override @@ -128,7 +128,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { .append(" isNrAvailable = " + isNrAvailable) .append(" isEnDcAvailable = " + isEnDcAvailable) .append(" " + mLteVopsSupportInfo.toString()) - .append(" isUsingCarrierAggregation = " + isUsingCarrierAggregation) + .append(" mIsUsingCarrierAggregation = " + mIsUsingCarrierAggregation) .append(" }") .toString(); } @@ -136,7 +136,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { @Override public int hashCode() { return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable, - mLteVopsSupportInfo, isUsingCarrierAggregation); + mLteVopsSupportInfo, mIsUsingCarrierAggregation); } @Override @@ -151,7 +151,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { && this.isNrAvailable == other.isNrAvailable && this.isEnDcAvailable == other.isEnDcAvailable && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo) - && this.isUsingCarrierAggregation == other.isUsingCarrierAggregation; + && this.mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation; } public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR = @@ -174,4 +174,22 @@ public final class DataSpecificRegistrationInfo implements Parcelable { public LteVopsSupportInfo getLteVopsSupportInfo() { return mLteVopsSupportInfo; } + + /** + * Set the flag indicating if using carrier aggregation. + * + * @param isUsingCarrierAggregation {@code true} if using carrier aggregation. + * @hide + */ + public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) { + mIsUsingCarrierAggregation = isUsingCarrierAggregation; + } + + /** + * @return {@code true} if using carrier aggregation. + * @hide + */ + public boolean isUsingCarrierAggregation() { + return mIsUsingCarrierAggregation; + } } diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index 2bb02e7af1e0..7b9f6d5eb8a1 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -368,6 +368,13 @@ public final class NetworkRegistrationInfo implements Parcelable { * @hide */ public void setAccessNetworkTechnology(@NetworkType int tech) { + if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) { + // For old device backward compatibility support + tech = TelephonyManager.NETWORK_TYPE_LTE; + if (mDataSpecificInfo != null) { + mDataSpecificInfo.setIsUsingCarrierAggregation(true); + } + } mAccessNetworkTechnology = tech; } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 549c04420ce0..b75e51577fdb 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -2016,7 +2016,16 @@ public class PhoneNumberUtils { private static boolean isEmergencyNumberInternal(int subId, String number, String defaultCountryIso, boolean useExactMatch) { - return TelephonyManager.getDefault().isEmergencyNumber(number); + try { + if (useExactMatch) { + return TelephonyManager.getDefault().isEmergencyNumber(number); + } else { + return TelephonyManager.getDefault().isPotentialEmergencyNumber(number); + } + } catch (RuntimeException ex) { + Rlog.e(LOG_TAG, "isEmergencyNumberInternal: RuntimeException: " + ex); + } + return false; } /** diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index a794ba12f202..d2c070593401 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -312,18 +312,6 @@ public class ServiceState implements Parcelable { private boolean mIsManualNetworkSelection; private boolean mIsEmergencyOnly; - /** - * TODO: remove mRilVoiceRadioTechnology after completely migrate to - * {@link TelephonyManager.NetworkType} - */ - @RilRadioTechnology - private int mRilVoiceRadioTechnology; - /** - * TODO: remove mRilDataRadioTechnology after completely migrate to - * {@link TelephonyManager.NetworkType} - */ - @RilRadioTechnology - private int mRilDataRadioTechnology; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private boolean mCssIndicator; @@ -340,9 +328,6 @@ public class ServiceState implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private int mCdmaEriIconMode; - @UnsupportedAppUsage - private boolean mIsUsingCarrierAggregation; - @FrequencyRange private int mNrFrequencyRange; private int mChannelNumber; @@ -420,8 +405,6 @@ public class ServiceState implements Parcelable { mDataOperatorAlphaShort = s.mDataOperatorAlphaShort; mDataOperatorNumeric = s.mDataOperatorNumeric; mIsManualNetworkSelection = s.mIsManualNetworkSelection; - mRilVoiceRadioTechnology = s.mRilVoiceRadioTechnology; - mRilDataRadioTechnology = s.mRilDataRadioTechnology; mCssIndicator = s.mCssIndicator; mNetworkId = s.mNetworkId; mSystemId = s.mSystemId; @@ -430,7 +413,6 @@ public class ServiceState implements Parcelable { mCdmaEriIconIndex = s.mCdmaEriIconIndex; mCdmaEriIconMode = s.mCdmaEriIconMode; mIsEmergencyOnly = s.mIsEmergencyOnly; - mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation; mChannelNumber = s.mChannelNumber; mCellBandwidths = s.mCellBandwidths == null ? null : Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length); @@ -457,8 +439,6 @@ public class ServiceState implements Parcelable { mDataOperatorAlphaShort = in.readString(); mDataOperatorNumeric = in.readString(); mIsManualNetworkSelection = in.readInt() != 0; - mRilVoiceRadioTechnology = in.readInt(); - mRilDataRadioTechnology = in.readInt(); mCssIndicator = (in.readInt() != 0); mNetworkId = in.readInt(); mSystemId = in.readInt(); @@ -467,7 +447,6 @@ public class ServiceState implements Parcelable { mCdmaEriIconIndex = in.readInt(); mCdmaEriIconMode = in.readInt(); mIsEmergencyOnly = in.readInt() != 0; - mIsUsingCarrierAggregation = in.readInt() != 0; mLteEarfcnRsrpBoost = in.readInt(); mNetworkRegistrationInfos = new ArrayList<>(); in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader()); @@ -486,8 +465,6 @@ public class ServiceState implements Parcelable { out.writeString(mDataOperatorAlphaShort); out.writeString(mDataOperatorNumeric); out.writeInt(mIsManualNetworkSelection ? 1 : 0); - out.writeInt(mRilVoiceRadioTechnology); - out.writeInt(mRilDataRadioTechnology); out.writeInt(mCssIndicator ? 1 : 0); out.writeInt(mNetworkId); out.writeInt(mSystemId); @@ -496,7 +473,6 @@ public class ServiceState implements Parcelable { out.writeInt(mCdmaEriIconIndex); out.writeInt(mCdmaEriIconMode); out.writeInt(mIsEmergencyOnly ? 1 : 0); - out.writeInt(mIsUsingCarrierAggregation ? 1 : 0); out.writeInt(mLteEarfcnRsrpBoost); out.writeList(mNetworkRegistrationInfos); out.writeInt(mChannelNumber); @@ -568,7 +544,7 @@ public class ServiceState implements Parcelable { @DuplexMode public int getDuplexMode() { // only support LTE duplex mode - if (!isLte(mRilDataRadioTechnology)) { + if (!isLte(getRilDataRadioTechnology())) { return DUPLEX_MODE_UNKNOWN; } @@ -850,8 +826,6 @@ public class ServiceState implements Parcelable { mDataOperatorAlphaShort, mDataOperatorNumeric, mIsManualNetworkSelection, - mRilVoiceRadioTechnology, - mRilDataRadioTechnology, mCssIndicator, mNetworkId, mSystemId, @@ -860,7 +834,6 @@ public class ServiceState implements Parcelable { mCdmaEriIconIndex, mCdmaEriIconMode, mIsEmergencyOnly, - mIsUsingCarrierAggregation, mLteEarfcnRsrpBoost, mNetworkRegistrationInfos, mNrFrequencyRange); @@ -871,7 +844,7 @@ public class ServiceState implements Parcelable { if (!(o instanceof ServiceState)) return false; ServiceState s = (ServiceState) o; - return (mVoiceRegState == s.mVoiceRegState + return mVoiceRegState == s.mVoiceRegState && mDataRegState == s.mDataRegState && mIsManualNetworkSelection == s.mIsManualNetworkSelection && mChannelNumber == s.mChannelNumber @@ -882,8 +855,6 @@ public class ServiceState implements Parcelable { && equalsHandlesNulls(mDataOperatorAlphaLong, s.mDataOperatorAlphaLong) && equalsHandlesNulls(mDataOperatorAlphaShort, s.mDataOperatorAlphaShort) && equalsHandlesNulls(mDataOperatorNumeric, s.mDataOperatorNumeric) - && equalsHandlesNulls(mRilVoiceRadioTechnology, s.mRilVoiceRadioTechnology) - && equalsHandlesNulls(mRilDataRadioTechnology, s.mRilDataRadioTechnology) && equalsHandlesNulls(mCssIndicator, s.mCssIndicator) && equalsHandlesNulls(mNetworkId, s.mNetworkId) && equalsHandlesNulls(mSystemId, s.mSystemId) @@ -891,7 +862,6 @@ public class ServiceState implements Parcelable { && equalsHandlesNulls(mCdmaDefaultRoamingIndicator, s.mCdmaDefaultRoamingIndicator) && mIsEmergencyOnly == s.mIsEmergencyOnly - && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation) && (mNetworkRegistrationInfos == null ? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null && mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos)) @@ -1035,27 +1005,27 @@ public class ServiceState implements Parcelable { .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort) .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection) .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)") - .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology) - .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")") - .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology) - .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")") + .append(", getRilVoiceRadioTechnology=").append(getRilVoiceRadioTechnology()) + .append("(" + rilRadioTechnologyToString(getRilVoiceRadioTechnology()) + ")") + .append(", getRilDataRadioTechnology=").append(getRilDataRadioTechnology()) + .append("(" + rilRadioTechnologyToString(getRilDataRadioTechnology()) + ")") .append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported") .append(", mNetworkId=").append(mNetworkId) .append(", mSystemId=").append(mSystemId) .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator) .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator) .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly) - .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation) + .append(", isUsingCarrierAggregation=").append(isUsingCarrierAggregation()) .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost) .append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos) .append(", mNrFrequencyRange=").append(mNrFrequencyRange) .append("}").toString(); } - private void setNullState(int state) { - if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state); - mVoiceRegState = state; - mDataRegState = state; + private void init() { + if (DBG) Rlog.d(LOG_TAG, "init"); + mVoiceRegState = STATE_OUT_OF_SERVICE; + mDataRegState = STATE_OUT_OF_SERVICE; mChannelNumber = -1; mCellBandwidths = new int[0]; mVoiceOperatorAlphaLong = null; @@ -1065,8 +1035,6 @@ public class ServiceState implements Parcelable { mDataOperatorAlphaShort = null; mDataOperatorNumeric = null; mIsManualNetworkSelection = false; - mRilVoiceRadioTechnology = 0; - mRilDataRadioTechnology = 0; mCssIndicator = false; mNetworkId = -1; mSystemId = -1; @@ -1075,18 +1043,28 @@ public class ServiceState implements Parcelable { mCdmaEriIconIndex = -1; mCdmaEriIconMode = -1; mIsEmergencyOnly = false; - mIsUsingCarrierAggregation = false; mLteEarfcnRsrpBoost = 0; - mNetworkRegistrationInfos = new ArrayList<>(); mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN; + addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_CS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) + .build()); + addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder() + .setDomain(NetworkRegistrationInfo.DOMAIN_PS) + .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN) + .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN) + .build()); } public void setStateOutOfService() { - setNullState(STATE_OUT_OF_SERVICE); + init(); } public void setStateOff() { - setNullState(STATE_POWER_OFF); + init(); + mVoiceRegState = STATE_POWER_OFF; + mDataRegState = STATE_POWER_OFF; } public void setState(int state) { @@ -1304,8 +1282,8 @@ public class ServiceState implements Parcelable { m.putString("data-operator-alpha-short", mDataOperatorAlphaShort); m.putString("data-operator-numeric", mDataOperatorNumeric); m.putBoolean("manual", mIsManualNetworkSelection); - m.putInt("radioTechnology", mRilVoiceRadioTechnology); - m.putInt("dataRadioTechnology", mRilDataRadioTechnology); + m.putInt("radioTechnology", getRilVoiceRadioTechnology()); + m.putInt("dataRadioTechnology", getRadioTechnology()); m.putBoolean("cssIndicator", mCssIndicator); m.putInt("networkId", mNetworkId); m.putInt("systemId", mSystemId); @@ -1313,7 +1291,7 @@ public class ServiceState implements Parcelable { m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator); m.putBoolean("emergencyOnly", mIsEmergencyOnly); m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration()); - m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation); + m.putBoolean("isUsingCarrierAggregation", isUsingCarrierAggregation()); m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost); m.putInt("ChannelNumber", mChannelNumber); m.putIntArray("CellBandwidths", mCellBandwidths); @@ -1323,13 +1301,9 @@ public class ServiceState implements Parcelable { /** @hide */ @TestApi public void setRilVoiceRadioTechnology(@RilRadioTechnology int rt) { - if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) { - rt = RIL_RADIO_TECHNOLOGY_LTE; - } - - this.mRilVoiceRadioTechnology = rt; - - // sync to network registration state + Rlog.e(LOG_TAG, "ServiceState.setRilVoiceRadioTechnology() called. It's encouraged to " + + "use addNetworkRegistrationInfo() instead *******"); + // Sync to network registration state NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); if (regState == null) { @@ -1339,24 +1313,18 @@ public class ServiceState implements Parcelable { .build(); addNetworkRegistrationInfo(regState); } - regState.setAccessNetworkTechnology( - rilRadioTechnologyToNetworkType(mRilVoiceRadioTechnology)); + regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt)); } + /** @hide */ @TestApi public void setRilDataRadioTechnology(@RilRadioTechnology int rt) { - if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) { - rt = RIL_RADIO_TECHNOLOGY_LTE; - this.mIsUsingCarrierAggregation = true; - } else { - this.mIsUsingCarrierAggregation = false; - } - this.mRilDataRadioTechnology = rt; - if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" + - mRilDataRadioTechnology); - - // sync to network registration state + Rlog.e(LOG_TAG, "ServiceState.setRilDataRadioTechnology() called. It's encouraged to " + + "use addNetworkRegistrationInfo() instead *******"); + // Sync to network registration state. Always write down the WWAN transport. For AP-assisted + // mode device, use addNetworkRegistrationInfo() to set the correct transport if RAT + // is IWLAN. NetworkRegistrationInfo regState = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); @@ -1367,18 +1335,32 @@ public class ServiceState implements Parcelable { .build(); addNetworkRegistrationInfo(regState); } - regState.setAccessNetworkTechnology( - rilRadioTechnologyToNetworkType(mRilDataRadioTechnology)); + regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt)); } /** @hide */ public boolean isUsingCarrierAggregation() { - return mIsUsingCarrierAggregation; + NetworkRegistrationInfo nri = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null) { + DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); + if (dsri != null) { + return dsri.isUsingCarrierAggregation(); + } + } + return false; } /** @hide */ public void setIsUsingCarrierAggregation(boolean ca) { - mIsUsingCarrierAggregation = ca; + NetworkRegistrationInfo nri = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (nri != null) { + DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo(); + if (dsri != null) { + dsri.setIsUsingCarrierAggregation(ca); + } + } } /** @@ -1435,12 +1417,29 @@ public class ServiceState implements Parcelable { /** @hide */ @UnsupportedAppUsage public int getRilVoiceRadioTechnology() { - return this.mRilVoiceRadioTechnology; + NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + if (wwanRegInfo != null) { + return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology()); + } + return RIL_RADIO_TECHNOLOGY_UNKNOWN; } /** @hide */ @UnsupportedAppUsage public int getRilDataRadioTechnology() { - return this.mRilDataRadioTechnology; + NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); + NetworkRegistrationInfo wlanRegInfo = getNetworkRegistrationInfo( + NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); + if (wlanRegInfo != null + && wlanRegInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN + && wlanRegInfo.getRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { + return RIL_RADIO_TECHNOLOGY_IWLAN; + } else if (wwanRegInfo != null) { + return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology()); + } + return RIL_RADIO_TECHNOLOGY_UNKNOWN; } /** * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f393cba4b8f1..bdd01e2f69fb 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10861,24 +10861,28 @@ public class TelephonyManager { } /** - * Get whether reboot is required or not after making changes to modem configurations. + * Get whether making changes to modem configurations by {@link #switchMultiSimConfig(int)} will + * trigger device reboot. * The modem configuration change refers to switching from single SIM configuration to DSDS * or the other way around. - * @Return {@code true} if reboot is required after making changes to modem configurations, - * otherwise return {@code false}. * - * @hide + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or that the + * calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * + * @return {@code true} if reboot will be triggered after making changes to modem + * configurations, otherwise return {@code false}. */ - @SystemApi - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public boolean isRebootRequiredForModemConfigChange() { + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + public boolean doesSwitchMultiSimConfigTriggerReboot() { try { ITelephony service = getITelephony(); if (service != null) { - return service.isRebootRequiredForModemConfigChange(); + return service.doesSwitchMultiSimConfigTriggerReboot(getSubId(), + getOpPackageName()); } } catch (RemoteException e) { - Log.e(TAG, "isRebootRequiredForModemConfigChange RemoteException", e); + Log.e(TAG, "doesSwitchMultiSimConfigTriggerReboot RemoteException", e); } return false; } diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index cde10ea7cd09..96a2514e8ff0 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -485,7 +485,7 @@ public class EuiccManager { public boolean isEnabled() { // In the future, this may reach out to IEuiccController (if non-null) to check any dynamic // restrictions. - return getIEuiccController() != null; + return getIEuiccController() != null && refreshCardIdIfUninitialized(); } /** @@ -499,7 +499,7 @@ public class EuiccManager { */ @Nullable public String getEid() { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { return null; } try { @@ -522,7 +522,7 @@ public class EuiccManager { @SystemApi @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus() { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { return EUICC_OTA_STATUS_UNAVAILABLE; } try { @@ -557,7 +557,7 @@ public class EuiccManager { @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void downloadSubscription(DownloadableSubscription subscription, boolean switchAfterDownload, PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -619,7 +619,7 @@ public class EuiccManager { @SystemApi @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { PendingIntent callbackIntent = resolutionIntent.getParcelableExtra( EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT); @@ -656,7 +656,7 @@ public class EuiccManager { @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata( DownloadableSubscription subscription, PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -686,7 +686,7 @@ public class EuiccManager { @SystemApi @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -705,7 +705,7 @@ public class EuiccManager { */ @Nullable public EuiccInfo getEuiccInfo() { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { return null; } try { @@ -730,7 +730,7 @@ public class EuiccManager { */ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -770,7 +770,7 @@ public class EuiccManager { */ @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -796,7 +796,7 @@ public class EuiccManager { @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void updateSubscriptionNickname( int subscriptionId, @Nullable String nickname, @NonNull PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -820,7 +820,7 @@ public class EuiccManager { @SystemApi @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } @@ -850,7 +850,7 @@ public class EuiccManager { * @hide */ public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) { - if (!refreshCardIdIfUninitialized()) { + if (!isEnabled()) { sendUnavailableError(callbackIntent); return; } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 8332ffe889f3..c8cd2495bdd9 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1945,10 +1945,10 @@ interface ITelephony { void switchMultiSimConfig(int numOfSims); /** - * Get if reboot is required upon altering modems configurations + * Get if altering modems configurations will trigger reboot. * @hide */ - boolean isRebootRequiredForModemConfigChange(); + boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage); /** * Get the mapping from logical slots to physical slots. diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java index fb84611cb662..a83faf34776d 100644 --- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java +++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net.ipmemorystore; +package com.android.server.connectivity.ipmemorystore; import static org.junit.Assert.assertEquals; |