diff options
321 files changed, 7450 insertions, 3640 deletions
diff --git a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java index e4a850335aad..e126fb807b99 100644 --- a/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java +++ b/apct-tests/perftests/core/src/android/os/BinderCallsStatsPerfTest.java @@ -45,7 +45,7 @@ public class BinderCallsStatsPerfTest { @Before public void setUp() { - mBinderCallsStats = new BinderCallsStats(true); + mBinderCallsStats = new BinderCallsStats(); } @After @@ -54,6 +54,7 @@ public class BinderCallsStatsPerfTest { @Test public void timeCallSession() { + mBinderCallsStats.setDetailedTracking(true); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); Binder b = new Binder(); int i = 0; @@ -66,9 +67,9 @@ public class BinderCallsStatsPerfTest { @Test public void timeCallSessionTrackingDisabled() { + mBinderCallsStats.setDetailedTracking(false); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); Binder b = new Binder(); - mBinderCallsStats = new BinderCallsStats(false); while (state.keepRunning()) { BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, 0); mBinderCallsStats.callEnded(s, 0, 0); diff --git a/api/current.txt b/api/current.txt index 8892b247f31c..dcc19e62d187 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6120,8 +6120,10 @@ package android.app { } public final class UiAutomation { + method public void adoptShellPermissionIdentity(); method public void clearWindowAnimationFrameStats(); method public boolean clearWindowContentFrameStats(int); + method public void dropShellPermissionIdentity(); method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException; method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); @@ -39666,6 +39668,7 @@ package android.service.voice { field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10 field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8 field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 + field public static final int SHOW_SOURCE_PUSH_TO_TALK = 32; // 0x20 field public static final int SHOW_WITH_ASSIST = 1; // 0x1 field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2 } @@ -42411,8 +42414,10 @@ package android.telephony { method public java.lang.CharSequence getDisplayName(); method public java.lang.String getIccId(); method public int getIconTint(); - method public int getMcc(); - method public int getMnc(); + method public deprecated int getMcc(); + method public java.lang.String getMccString(); + method public deprecated int getMnc(); + method public java.lang.String getMncString(); method public java.lang.String getNumber(); method public int getSimSlotIndex(); method public int getSubscriptionId(); @@ -42505,9 +42510,13 @@ package android.telephony { method public java.lang.String getIccAuthentication(int, int, java.lang.String); method public java.lang.String getImei(); method public java.lang.String getImei(int); + method public java.lang.String getTypeAllocationCode(); + method public java.lang.String getTypeAllocationCode(int); method public java.lang.String getLine1Number(); method public java.lang.String getMeid(); method public java.lang.String getMeid(int); + method public java.lang.String getManufacturerCode(); + method public java.lang.String getManufacturerCode(int); method public java.lang.String getMmsUAProfUrl(); method public java.lang.String getMmsUserAgent(); method public java.lang.String getNai(); diff --git a/api/test-current.txt b/api/test-current.txt index e05257818bc7..e5061ed32a9e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -274,7 +274,9 @@ package android.content.pm { method public abstract java.lang.String getPermissionControllerPackageName(); method public abstract java.lang.String getServicesSystemSharedLibraryPackageName(); method public abstract java.lang.String getSharedSystemSharedLibraryPackageName(); + method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public abstract boolean isPermissionReviewModeEnabled(); + method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage"; field public static final java.lang.String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption"; field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index 6e0bd3a81d84..36e51b9703c9 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -462,7 +462,7 @@ public class Content { IBinder token = new Binder(); try { ContentProviderHolder holder = activityManager.getContentProviderExternal( - providerName, mUserId, token); + providerName, mUserId, token, "*cmd*"); if (holder == null) { throw new IllegalStateException("Could not find provider: " + providerName); } diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java index 653851546d01..950a258d123d 100644 --- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java +++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java @@ -62,7 +62,7 @@ public class ShellUiAutomatorBridge extends UiAutomatorBridge { IBinder token = new Binder(); try { ContentProviderHolder holder = activityManager.getContentProviderExternal( - providerName, UserHandle.USER_SYSTEM, token); + providerName, UserHandle.USER_SYSTEM, token, "*uiautomator*"); if (holder == null) { throw new IllegalStateException("Could not find provider: " + providerName); } diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index ed06f2aaf12e..7a9a553bb287 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -22,6 +22,7 @@ import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.os.Bundle; import android.os.IBinder; @@ -216,4 +217,16 @@ public abstract class ActivityManagerInternal { public abstract void updateOomAdj(); public abstract void sendForegroundProfileChanged(int userId); + + /** + * Returns whether the given user requires credential entry at this time. This is used to + * intercept activity launches for work apps when the Work Challenge is present. + */ + public abstract boolean shouldConfirmCredentials(int userId); + public abstract int[] getCurrentProfileIds(); + public abstract UserInfo getCurrentUser(); + public abstract void ensureNotSpecialUser(int userId); + public abstract boolean isCurrentProfile(int userId); + public abstract boolean hasStartedUserState(int userId); + public abstract void finishUserSwitch(Object uss); } diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 89408cc340d9..89145351655a 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -302,7 +302,6 @@ public class ActivityOptions { private int mResultCode; private int mExitCoordinatorIndex; private PendingIntent mUsageTimeReport; - private boolean mLockTaskMode = false; private int mLaunchDisplayId = INVALID_DISPLAY; @WindowConfiguration.WindowingMode private int mLaunchWindowingMode = WINDOWING_MODE_UNDEFINED; @@ -310,6 +309,7 @@ public class ActivityOptions { private int mLaunchActivityType = ACTIVITY_TYPE_UNDEFINED; private int mLaunchTaskId = -1; private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; + private boolean mLockTaskMode = false; private boolean mDisallowEnterPictureInPictureWhileLaunching; private boolean mTaskOverlay; private boolean mTaskOverlayCanResume; @@ -946,7 +946,7 @@ public class ActivityOptions { mAnimationFinishedListener = IRemoteCallback.Stub.asInterface( opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER)); } - mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT); + mRotationAnimationHint = opts.getInt(KEY_ROTATION_ANIMATION_HINT, -1); mAppVerificationBundle = opts.getBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE); if (opts.containsKey(KEY_SPECS_FUTURE)) { mSpecsFuture = IAppTransitionAnimationSpecsFuture.Stub.asInterface(opts.getBinder( @@ -1442,17 +1442,37 @@ public class ActivityOptions { b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex); break; } - b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode); - b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId); - b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode); - b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType); - b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); - b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay); - b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume); - b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront); - b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode); - b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, - mDisallowEnterPictureInPictureWhileLaunching); + if (mLockTaskMode) { + b.putBoolean(KEY_LOCK_TASK_MODE, mLockTaskMode); + } + if (mLaunchDisplayId != INVALID_DISPLAY) { + b.putInt(KEY_LAUNCH_DISPLAY_ID, mLaunchDisplayId); + } + if (mLaunchWindowingMode != WINDOWING_MODE_UNDEFINED) { + b.putInt(KEY_LAUNCH_WINDOWING_MODE, mLaunchWindowingMode); + } + if (mLaunchActivityType != ACTIVITY_TYPE_UNDEFINED) { + b.putInt(KEY_LAUNCH_ACTIVITY_TYPE, mLaunchActivityType); + } + if (mLaunchTaskId != -1) { + b.putInt(KEY_LAUNCH_TASK_ID, mLaunchTaskId); + } + if (mTaskOverlay) { + b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay); + } + if (mTaskOverlayCanResume) { + b.putBoolean(KEY_TASK_OVERLAY_CAN_RESUME, mTaskOverlayCanResume); + } + if (mAvoidMoveToFront) { + b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront); + } + if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) { + b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode); + } + if (mDisallowEnterPictureInPictureWhileLaunching) { + b.putBoolean(KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, + mDisallowEnterPictureInPictureWhileLaunching); + } if (mAnimSpecs != null) { b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs); } @@ -1462,7 +1482,9 @@ public class ActivityOptions { if (mSpecsFuture != null) { b.putBinder(KEY_SPECS_FUTURE, mSpecsFuture.asBinder()); } - b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint); + if (mRotationAnimationHint != -1) { + b.putInt(KEY_ROTATION_ANIMATION_HINT, mRotationAnimationHint); + } if (mAppVerificationBundle != null) { b.putBundle(KEY_INSTANT_APP_VERIFICATION_BUNDLE, mAppVerificationBundle); } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 8b3396392c3f..c3404a5c79e2 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2487,7 +2487,7 @@ public class AppOpsManager { */ public int noteProxyOpNoThrow(int op, String proxiedPackageName) { try { - return mService.noteProxyOperation(op, mContext.getOpPackageName(), + return mService.noteProxyOperation(op, Process.myUid(), mContext.getOpPackageName(), Binder.getCallingUid(), proxiedPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 24c5d234c120..f5d5e6e9a950 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -18,12 +18,55 @@ package android.app; import android.util.SparseIntArray; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.TriFunction; + /** * App ops service local interface. * * @hide Only for use within the system server. */ public abstract class AppOpsManagerInternal { + /** Interface to override app ops checks via composition */ + public interface CheckOpsDelegate { + /** + * Allows overriding check operation behavior. + * + * @param code The op code to check. + * @param uid The UID for which to check. + * @param packageName The package for which to check. + * @param superImpl The super implementation. + * @return The app op check result. + */ + int checkOperation(int code, int uid, String packageName, + TriFunction<Integer, Integer, String, Integer> superImpl); + + /** + * Allows overriding check audio operation behavior. + * + * @param code The op code to check. + * @param usage The audio op usage. + * @param uid The UID for which to check. + * @param packageName The package for which to check. + * @param superImpl The super implementation. + * @return The app op check result. + */ + int checkAudioOperation(int code, int usage, int uid, String packageName, + QuadFunction<Integer, Integer, Integer, String, Integer> superImpl); + + /** + * Allows overriding note operation behavior. + * + * @param code The op code to note. + * @param uid The UID for which to note. + * @param packageName The package for which to note. + * @param superImpl The super implementation. + * @return The app op note result. + */ + int noteOperation(int code, int uid, String packageName, + TriFunction<Integer, Integer, String, Integer> superImpl); + } + /** * Set the currently configured device and profile owners. Specifies the package uid (value) * that has been configured for each user (key) that has one. These will be allowed privileged diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 76244ea3180c..19d7c83818f6 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -268,7 +268,7 @@ interface IActivityManager { void showBootMessage(in CharSequence msg, boolean always); void killAllBackgroundProcesses(); ContentProviderHolder getContentProviderExternal(in String name, int userId, - in IBinder token); + in IBinder token, String tag); void removeContentProviderExternal(in String name, in IBinder token); // Get memory information about the calling process. void getMyMemoryState(out ActivityManager.RunningAppProcessInfo outInfo); @@ -498,4 +498,19 @@ interface IActivityManager { * user unlock progress. */ boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener); + + /** + * Method for the shell UID to start deletating its permission identity to an + * active instrumenation. The shell can delegate permissions only to one active + * instrumentation at a time. An active instrumentation is one running and + * started from the shell. + */ + void startDelegateShellPermissionIdentity(int uid); + + /** + * Method for the shell UID to stop deletating its permission identity to an + * active instrumenation. An active instrumentation is one running and + * started from the shell. + */ + void stopDelegateShellPermissionIdentity(); } diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl index d01938b123b1..ac4bf7d9c2c5 100644 --- a/core/java/android/app/IUiAutomationConnection.aidl +++ b/core/java/android/app/IUiAutomationConnection.aidl @@ -47,7 +47,8 @@ interface IUiAutomationConnection { in ParcelFileDescriptor source); void grantRuntimePermission(String packageName, String permission, int userId); void revokeRuntimePermission(String packageName, String permission, int userId); - + void adoptShellPermissionIdentity(int uid); + void dropShellPermissionIdentity(); // Called from the system process. oneway void shutdown(); } diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 5662aeae8110..44f2879601b8 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -33,6 +33,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -50,6 +51,7 @@ import android.view.accessibility.AccessibilityWindowInfo; import android.view.accessibility.IAccessibilityInteractionConnection; import com.android.internal.util.function.pooled.PooledLambda; + import libcore.io.IoUtils; import java.io.IOException; @@ -347,6 +349,46 @@ public final class UiAutomation { } /** + * Adopt the permission identity of the shell UID. This allows you to call APIs protected + * permissions which normal apps cannot hold but are granted to the shell UID. If you + * already adopted the shell permission identity this method would be a no-op. + * Note that your permission state becomes that of the shell UID and it is not a + * combination of your and the shell UID permissions. + * + * @see #dropShellPermissionIdentity() + */ + public void adoptShellPermissionIdentity() { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + // Calling out without a lock held. + mUiAutomationConnection.adoptShellPermissionIdentity(Process.myUid()); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error executing adopting shell permission identity!", re); + } + } + + /** + * Drop the shell permission identity adopted by a previous call to + * {@link #adoptShellPermissionIdentity()}. If you did not adopt the shell permission + * identity this method would be a no-op. + * + * @see #adoptShellPermissionIdentity() + */ + public void dropShellPermissionIdentity() { + synchronized (mLock) { + throwIfNotConnectedLocked(); + } + try { + // Calling out without a lock held. + mUiAutomationConnection.dropShellPermissionIdentity(); + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error executing dropping shell permission identity!", re); + } + } + + /** * Performs a global action. Such an action can be performed at any moment * regardless of the current application or user location in that application. * For example going back, going home, opening recents, etc. @@ -999,6 +1041,8 @@ public final class UiAutomation { * * @param command The command to execute. * @return A file descriptor to the standard output stream. + * + * @see #adoptShellPermissionIdentity() */ public ParcelFileDescriptor executeShellCommand(String command) { synchronized (mLock) { @@ -1081,22 +1125,6 @@ public final class UiAutomation { return result; } - private static float getDegreesForRotation(int value) { - switch (value) { - case Surface.ROTATION_90: { - return 360f - 90f; - } - case Surface.ROTATION_180: { - return 360f - 180f; - } - case Surface.ROTATION_270: { - return 360f - 270f; - } default: { - return 0; - } - } - } - private boolean isConnectedLocked() { return mConnectionId != CONNECTION_ID_UNDEFINED; } diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java index d3828ab47883..ac3f2e7a14d0 100644 --- a/core/java/android/app/UiAutomationConnection.java +++ b/core/java/android/app/UiAutomationConnection.java @@ -30,6 +30,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.util.Log; import android.view.IWindowManager; import android.view.InputEvent; import android.view.SurfaceControl; @@ -37,7 +38,6 @@ import android.view.WindowAnimationFrameStats; import android.view.WindowContentFrameStats; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.IAccessibilityManager; -import android.util.Log; import libcore.io.IoUtils; @@ -71,6 +71,9 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { private final IPackageManager mPackageManager = IPackageManager.Stub .asInterface(ServiceManager.getService("package")); + private final IActivityManager mActivityManager = IActivityManager.Stub + .asInterface(ServiceManager.getService("activity")); + private final Object mLock = new Object(); private final Binder mToken = new Binder(); @@ -274,6 +277,36 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { } } + @Override + public void adoptShellPermissionIdentity(int uid) throws RemoteException { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + mActivityManager.startDelegateShellPermissionIdentity(uid); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void dropShellPermissionIdentity() throws RemoteException { + synchronized (mLock) { + throwIfCalledByNotTrustedUidLocked(); + throwIfShutdownLocked(); + throwIfNotConnectedLocked(); + } + final long identity = Binder.clearCallingIdentity(); + try { + mActivityManager.stopDelegateShellPermissionIdentity(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + public class Repeater implements Runnable { // Continuously read readFrom and write back to writeTo until EOF is encountered private final InputStream readFrom; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 5e7f1e40f9c7..bbdc5323648d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4153,8 +4153,11 @@ public class DevicePolicyManager { * Called by a device or profile owner, or delegated certificate installer, to generate a * new private/public key pair. If the device supports key generation via secure hardware, * this method is useful for creating a key in KeyChain that never left the secure hardware. - * * Access to the key is controlled the same way as in {@link #installKeyPair}. + * + * <p>Because this method might take several seconds to complete, it should only be called from + * a worker thread. This method returns {@code null} when called from the main thread. + * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if calling from a delegated certificate installer. * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}. diff --git a/core/java/android/app/timezone/RulesState.aidl b/core/java/android/app/timezone/RulesState.aidl index f789120eb724..665220dddafd 100644 --- a/core/java/android/app/timezone/RulesState.aidl +++ b/core/java/android/app/timezone/RulesState.aidl @@ -14,4 +14,6 @@ * limitations under the License. */ +package android.app.timezone; + parcelable RulesState;
\ No newline at end of file diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a622af8f7660..ce551ee6d5ae 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3582,6 +3582,7 @@ public abstract class PackageManager { * * @hide */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String packageName, @@ -3608,6 +3609,7 @@ public abstract class PackageManager { * * @hide */ + @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String packageName, diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index f30b3fee7f46..ee752f8b8186 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -29,9 +29,12 @@ import android.os.Bundle; import android.os.PersistableBundle; import android.util.SparseArray; +import com.android.internal.util.function.TriFunction; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.function.BiFunction; /** * Package manager local system service interface. @@ -64,6 +67,32 @@ public abstract class PackageManagerInternal { void onPackageRemoved(@NonNull String packageName); } + /** Interface to override permission checks via composition */ + public interface CheckPermissionDelegate { + /** + * Allows overriding check permission behavior. + * + * @param permName The permission to check. + * @param pkgName The package for which to check. + * @param userId The user for which to check. + * @param superImpl The super implementation. + * @return The check permission result. + */ + int checkPermission(String permName, String pkgName, int userId, + TriFunction<String, String, Integer, Integer> superImpl); + + /** + * Allows overriding check UID permission behavior. + * + * @param permName The permission to check. + * @param uid The UID for which to check. + * @param superImpl The super implementation. + * @return The check permission result. + */ + int checkUidPermission(String permName, int uid, + BiFunction<String, Integer, Integer> superImpl); + } + /** * Provider for package names. */ @@ -628,4 +657,18 @@ public abstract class PackageManagerInternal { */ public abstract boolean hasSignatureCapability(int serverUid, int clientUid, @PackageParser.SigningDetails.CertCapabilities int capability); + + /** + * Get the delegate to influence permission checking. + * + * @return The delegate instance or null to clear. + */ + public abstract @Nullable CheckPermissionDelegate getCheckPermissionDelegate(); + + /** + * Set a delegate to influence permission checking. + * + * @param delegate A delegate instance or null to clear. + */ + public abstract void setCheckPermissionDelegate(@Nullable CheckPermissionDelegate delegate); } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 7adea6a880be..ef0dce3a2f64 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -642,8 +642,7 @@ public class Resources { * tool. This integer encodes the package, type, and resource * entry. The value 0 is an invalid identifier. * - * @return Resource dimension value multiplied by the appropriate - * metric. + * @return Resource dimension value multiplied by the appropriate metric to convert to pixels. * * @throws NotFoundException Throws NotFoundException if the given ID does not exist. * diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 221abed92f81..9cf7de586d17 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -247,8 +247,10 @@ public abstract class BatteryStats implements Parcelable { * - Deferred job metrics. * New in version 32: * - Ambient display properly output in data dump. + * New in version 33: + * - Fixed bug in min learned capacity updating process. */ - static final int CHECKIN_VERSION = 32; + static final int CHECKIN_VERSION = 33; /** * Old version, we hit 9 and ran out of room, need to remove. diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index ac871055dc4a..f31130f8645d 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -23,6 +23,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BinderCallsStats; import com.android.internal.os.BinderInternal; import com.android.internal.util.FastPrintWriter; @@ -730,7 +731,7 @@ public class Binder implements IBinder { } res = onTransact(code, data, reply, flags); } catch (RemoteException|RuntimeException e) { - binderCallsStats.callThrewException(callSession); + binderCallsStats.callThrewException(callSession, e); if (LOG_RUNTIME_EXCEPTION) { Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); } @@ -1027,19 +1028,19 @@ final class BinderProxy implements IBinder { new ArrayList[MAIN_INDEX_SIZE]; } - private static ProxyMap sProxyMap = new ProxyMap(); + @GuardedBy("sProxyMap") + private static final ProxyMap sProxyMap = new ProxyMap(); /** * Dump proxy debug information. * - * Note: this method is not thread-safe; callers must serialize with other - * accesses to sProxyMap, in particular {@link #getInstance(long, long)}. - * * @hide */ private static void dumpProxyDebugInfo() { if (Build.IS_DEBUGGABLE) { - sProxyMap.dumpProxyInterfaceCounts(); + synchronized (sProxyMap) { + sProxyMap.dumpProxyInterfaceCounts(); + } // Note that we don't call dumpPerUidProxyCounts(); this is because this // method may be called as part of the uid limit being hit, and calling // back into the UID tracking code would cause us to try to acquire a mutex @@ -1049,8 +1050,6 @@ final class BinderProxy implements IBinder { /** * Return a BinderProxy for IBinder. - * This method is thread-hostile! The (native) caller serializes getInstance() calls using - * gProxyLock. * If we previously returned a BinderProxy bp for the same iBinder, and bp is still * in use, then we return the same bp. * @@ -1062,21 +1061,23 @@ final class BinderProxy implements IBinder { */ private static BinderProxy getInstance(long nativeData, long iBinder) { BinderProxy result; - try { - result = sProxyMap.get(iBinder); - if (result != null) { - return result; + synchronized (sProxyMap) { + try { + result = sProxyMap.get(iBinder); + if (result != null) { + return result; + } + result = new BinderProxy(nativeData); + } catch (Throwable e) { + // We're throwing an exception (probably OOME); don't drop nativeData. + NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer, + nativeData); + throw e; } - result = new BinderProxy(nativeData); - } catch (Throwable e) { - // We're throwing an exception (probably OOME); don't drop nativeData. - NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer, - nativeData); - throw e; + NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData); + // The registry now owns nativeData, even if registration threw an exception. + sProxyMap.set(iBinder, result); } - NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData); - // The registry now owns nativeData, even if registration threw an exception. - sProxyMap.set(iBinder, result); return result; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index a7fcaffba30f..82b66d7b7925 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6029,6 +6029,15 @@ public final class Settings { NON_NEGATIVE_INTEGER_VALIDATOR; /** + * Whether the in call notification is enabled to play sound during calls. The value is + * boolean (1 or 0). + * @hide + */ + public static final String IN_CALL_NOTIFICATION_ENABLED = "in_call_notification_enabled"; + + private static final Validator IN_CALL_NOTIFICATION_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; + + /** * Uri of the slice that's presented on the keyguard. * Defaults to a slice with the date and next alarm. * @@ -6982,8 +6991,6 @@ public final class Settings { */ public static final String SELECTED_SPELL_CHECKER = "selected_spell_checker"; - private static final Validator SELECTED_SPELL_CHECKER_VALIDATOR = COMPONENT_NAME_VALIDATOR; - /** * {@link android.view.textservice.SpellCheckerSubtype#hashCode()} of the selected subtype * of the selected spell checker service which is one of the services managed by the text @@ -6994,9 +7001,6 @@ public final class Settings { public static final String SELECTED_SPELL_CHECKER_SUBTYPE = "selected_spell_checker_subtype"; - private static final Validator SELECTED_SPELL_CHECKER_SUBTYPE_VALIDATOR = - ANY_INTEGER_VALIDATOR; - /** * Whether spell checker is enabled or not. * @@ -7004,8 +7008,6 @@ public final class Settings { */ public static final String SPELL_CHECKER_ENABLED = "spell_checker_enabled"; - private static final Validator SPELL_CHECKER_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR; - /** * What happens when the user presses the Power button while in-call * and the screen is on.<br/> @@ -7124,35 +7126,6 @@ public final class Settings { public static final String UI_NIGHT_MODE = "ui_night_mode"; /** - * The current device UI theme mode effect SystemUI and Launcher.<br/> - * <b>Values:</b><br/> - * 0 - The mode that theme will controlled by wallpaper color.<br/> - * 1 - The mode that will always light theme.<br/> - * 2 - The mode that will always dark theme.<br/> - * - * @hide - */ - public static final String THEME_MODE = "theme_mode"; - - /** - * THEME_MODE value for wallpaper mode. - * @hide - */ - public static final int THEME_MODE_WALLPAPER = 0; - - /** - * THEME_MODE value for light theme mode. - * @hide - */ - public static final int THEME_MODE_LIGHT = 1; - - /** - * THEME_MODE value for dark theme mode. - * @hide - */ - public static final int THEME_MODE_DARK = 2; - - /** * Whether screensavers are enabled. * @hide */ @@ -7998,9 +7971,6 @@ public final class Settings { WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global - SELECTED_SPELL_CHECKER, - SELECTED_SPELL_CHECKER_SUBTYPE, - SPELL_CHECKER_ENABLED, MOUNT_PLAY_NOTIFICATION_SND, MOUNT_UMS_AUTOSTART, MOUNT_UMS_PROMPT, @@ -8048,6 +8018,7 @@ public final class Settings { VOLUME_HUSH_GESTURE, MANUAL_RINGER_TOGGLE_COUNT, HUSH_GESTURE_USED, + IN_CALL_NOTIFICATION_ENABLED, }; /** @@ -8124,10 +8095,6 @@ public final class Settings { VALIDATORS.put(WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY_VALIDATOR); VALIDATORS.put(WIFI_NUM_OPEN_NETWORKS_KEPT, WIFI_NUM_OPEN_NETWORKS_KEPT_VALIDATOR); - VALIDATORS.put(SELECTED_SPELL_CHECKER, SELECTED_SPELL_CHECKER_VALIDATOR); - VALIDATORS.put(SELECTED_SPELL_CHECKER_SUBTYPE, - SELECTED_SPELL_CHECKER_SUBTYPE_VALIDATOR); - VALIDATORS.put(SPELL_CHECKER_ENABLED, SPELL_CHECKER_ENABLED_VALIDATOR); VALIDATORS.put(MOUNT_PLAY_NOTIFICATION_SND, MOUNT_PLAY_NOTIFICATION_SND_VALIDATOR); VALIDATORS.put(MOUNT_UMS_AUTOSTART, MOUNT_UMS_AUTOSTART_VALIDATOR); VALIDATORS.put(MOUNT_UMS_PROMPT, MOUNT_UMS_PROMPT_VALIDATOR); @@ -8193,6 +8160,7 @@ public final class Settings { ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES_VALIDATOR); //legacy restore setting VALIDATORS.put(HUSH_GESTURE_USED, HUSH_GESTURE_USED_VALIDATOR); VALIDATORS.put(MANUAL_RINGER_TOGGLE_COUNT, MANUAL_RINGER_TOGGLE_COUNT_VALIDATOR); + VALIDATORS.put(IN_CALL_NOTIFICATION_ENABLED, IN_CALL_NOTIFICATION_ENABLED_VALIDATOR); } /** @@ -13011,6 +12979,21 @@ public final class Settings { */ public static final String GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS = "gnss_hal_location_request_duration_millis"; + + /** + * Binder call stats settings. + * + * The following strings are supported as keys: + * <pre> + * enabled (boolean) + * detailed_tracking (boolean) + * upload_data (boolean) + * sampling_interval (int) + * </pre> + * + * @hide + */ + public static final String BINDER_CALLS_STATS = "binder_calls_stats"; } /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 5546e803342b..df88e642a970 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -1007,6 +1007,24 @@ public class ZenModeConfig implements Parcelable { return true; } + /** + * Returns whether the conditionId is a valid ScheduleCondition. + * If allowNever is true, this will return true even if the ScheduleCondition never occurs. + */ + public static boolean isValidScheduleConditionId(Uri conditionId, boolean allowNever) { + ScheduleInfo info; + try { + info = tryParseScheduleConditionId(conditionId); + } catch (NullPointerException | ArrayIndexOutOfBoundsException e) { + return false; + } + + if (info == null || (!allowNever && (info.days == null || info.days.length == 0))) { + return false; + } + return true; + } + public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) { final boolean isSchedule = conditionId != null && conditionId.getScheme().equals(Condition.SCHEME) diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index cd177c42d6b3..26223f7bc6cd 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -109,6 +109,12 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall */ public static final int SHOW_SOURCE_ACTIVITY = 1<<4; + /** + * Flag for use with {@link #onShow}: indicates that the voice interaction service was invoked + * from a physical button. + */ + public static final int SHOW_SOURCE_PUSH_TO_TALK = 1 << 5; + final Context mContext; final HandlerCaller mHandlerCaller; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 6b7b89cfcc11..c037cd062b82 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -33,6 +33,8 @@ public class FeatureFlagUtils { public static final String FFLAG_PREFIX = "sys.fflag."; public static final String FFLAG_OVERRIDE_PREFIX = FFLAG_PREFIX + "override."; + public static final String PERSIST_PREFIX = "persist." + FFLAG_OVERRIDE_PREFIX; + public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid"; private static final Map<String, String> DEFAULT_FLAGS; static { @@ -42,6 +44,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_audio_switcher", "true"); DEFAULT_FLAGS.put("settings_systemui_theme", "true"); DEFAULT_FLAGS.put("settings_dynamic_homepage", "false"); + DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "true"); } /** diff --git a/core/java/android/util/Half.java b/core/java/android/util/Half.java index 84c2e8302e89..5718d994620d 100644 --- a/core/java/android/util/Half.java +++ b/core/java/android/util/Half.java @@ -20,8 +20,6 @@ import android.annotation.HalfFloat; import android.annotation.NonNull; import android.annotation.Nullable; -import sun.misc.FloatingDecimal; - /** * <p>The {@code Half} class is a wrapper and a utility class to manipulate half-precision 16-bit * <a href="https://en.wikipedia.org/wiki/Half-precision_floating-point_format">IEEE 754</a> @@ -1026,7 +1024,7 @@ public final class Half extends Number implements Comparable<Half> { * half-precision float value */ public static @HalfFloat short parseHalf(@NonNull String s) throws NumberFormatException { - return toHalf(FloatingDecimal.parseFloat(s)); + return toHalf(Float.parseFloat(s)); } /** diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java index 3617aa7212dc..5a74ec0e52c0 100644 --- a/core/java/android/util/IntArray.java +++ b/core/java/android/util/IntArray.java @@ -18,9 +18,11 @@ package android.util; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; -import java.util.Arrays; + import libcore.util.EmptyArray; +import java.util.Arrays; + /** * Implements a growing array of int primitives. * @@ -102,7 +104,7 @@ public class IntArray implements Cloneable { ensureCapacity(1); int rightSegment = mSize - index; mSize++; - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); if (rightSegment != 0) { // Move by 1 all values from the right of 'index' @@ -175,7 +177,7 @@ public class IntArray implements Cloneable { * Returns the value at the specified position in this array. */ public int get(int index) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); return mValues[index]; } @@ -183,7 +185,7 @@ public class IntArray implements Cloneable { * Sets the value at the specified position in this array. */ public void set(int index, int value) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); mValues[index] = value; } @@ -205,7 +207,7 @@ public class IntArray implements Cloneable { * Removes the value at the specified index from this array. */ public void remove(int index) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); mSize--; } @@ -223,10 +225,4 @@ public class IntArray implements Cloneable { public int[] toArray() { return Arrays.copyOf(mValues, mSize); } - - private void checkBounds(int index) { - if (index < 0 || mSize <= index) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - } } diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java index fa980966802f..5ed1c8c05cba 100644 --- a/core/java/android/util/LongArray.java +++ b/core/java/android/util/LongArray.java @@ -106,7 +106,7 @@ public class LongArray implements Cloneable { ensureCapacity(1); int rightSegment = mSize - index; mSize++; - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); if (rightSegment != 0) { // Move by 1 all values from the right of 'index' @@ -166,7 +166,7 @@ public class LongArray implements Cloneable { * Returns the value at the specified position in this array. */ public long get(int index) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); return mValues[index]; } @@ -174,7 +174,7 @@ public class LongArray implements Cloneable { * Sets the value at the specified position in this array. */ public void set(int index, long value) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); mValues[index] = value; } @@ -196,7 +196,7 @@ public class LongArray implements Cloneable { * Removes the value at the specified index from this array. */ public void remove(int index) { - checkBounds(index); + ArrayUtils.checkBounds(mSize, index); System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); mSize--; } @@ -215,12 +215,6 @@ public class LongArray implements Cloneable { return Arrays.copyOf(mValues, mSize); } - private void checkBounds(int index) { - if (index < 0 || mSize <= index) { - throw new ArrayIndexOutOfBoundsException(mSize, index); - } - } - /** * Test if each element of {@code a} equals corresponding element from {@code b} */ diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java index 47bda538ae52..496bc9ff5383 100644 --- a/core/java/android/view/DisplayCutout.java +++ b/core/java/android/view/DisplayCutout.java @@ -29,6 +29,7 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; +import android.graphics.Region.Op; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -325,14 +326,9 @@ public final class DisplayCutout { * @hide */ public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) { - Path path = new Path(); - path.reset(); - path.moveTo(left, top); - path.lineTo(left, bottom); - path.lineTo(right, bottom); - path.lineTo(right, top); - path.close(); - return fromBounds(path); + Region r = Region.obtain(); + r.set(left, top, right, bottom); + return fromBounds(r); } /** @@ -340,26 +336,19 @@ public final class DisplayCutout { * * @hide */ - public static DisplayCutout fromBounds(Path path) { - RectF clipRect = new RectF(); - path.computeBounds(clipRect, false /* unused */); - Region clipRegion = Region.obtain(); - clipRegion.set((int) clipRect.left, (int) clipRect.top, - (int) clipRect.right, (int) clipRect.bottom); - - Region bounds = new Region(); - bounds.setPath(path, clipRegion); - clipRegion.recycle(); - return new DisplayCutout(ZERO_RECT, bounds, false /* copyArguments */); + public static DisplayCutout fromBounds(Region region) { + return new DisplayCutout(ZERO_RECT, region, false /* copyArguments */); } /** - * Creates the bounding path according to @android:string/config_mainBuiltInDisplayCutout. + * Creates the display cutout according to + * @android:string/config_mainBuiltInDisplayCutoutRectApproximation, which is the closest + * rectangle-base approximation of the cutout. * * @hide */ - public static DisplayCutout fromResources(Resources res, int displayWidth, int displayHeight) { - return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), + public static DisplayCutout fromResourcesRectApproximation(Resources res, int displayWidth, int displayHeight) { + return fromSpec(res.getString(R.string.config_mainBuiltInDisplayCutoutRectApproximation), displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT); } @@ -369,7 +358,8 @@ public final class DisplayCutout { * @hide */ public static Path pathFromResources(Resources res, int displayWidth, int displayHeight) { - return pathAndDisplayCutoutFromSpec(res.getString(R.string.config_mainBuiltInDisplayCutout), + return pathAndDisplayCutoutFromSpec( + res.getString(R.string.config_mainBuiltInDisplayCutout), displayWidth, displayHeight, DENSITY_DEVICE_STABLE / (float) DENSITY_DEFAULT).first; } @@ -417,6 +407,7 @@ public final class DisplayCutout { } final Path p; + final Region r = Region.obtain(); try { p = PathParser.createPathFromPathData(spec); } catch (Throwable e) { @@ -431,6 +422,8 @@ public final class DisplayCutout { m.postTranslate(offsetX, 0); p.transform(m); + addToRegion(p, r); + if (bottomSpec != null) { final Path bottomPath; try { @@ -443,9 +436,10 @@ public final class DisplayCutout { m.postTranslate(0, displayHeight); bottomPath.transform(m); p.addPath(bottomPath); + addToRegion(bottomPath, r); } - final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(p)); + final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r)); synchronized (CACHE_LOCK) { sCachedSpec = spec; sCachedDisplayWidth = displayWidth; @@ -456,6 +450,14 @@ public final class DisplayCutout { return result; } + private static void addToRegion(Path p, Region r) { + final RectF rectF = new RectF(); + final Rect rect = new Rect(); + p.computeBounds(rectF, false /* unused */); + rectF.round(rect); + r.op(rect, Op.UNION); + } + private static Region boundingRectsToRegion(List<Rect> rects) { Region result = Region.obtain(); if (rects != null) { diff --git a/core/java/android/view/InputEvent.java b/core/java/android/view/InputEvent.java index 1f2aab94958c..c25736495b0e 100644 --- a/core/java/android/view/InputEvent.java +++ b/core/java/android/view/InputEvent.java @@ -95,6 +95,19 @@ public abstract class InputEvent implements Parcelable { } /** + * Gets the display id of the event. + * @return The display id associated with the event. + * @hide + */ + public abstract int getDisplayId(); + + /** + * Modifies the display id associated with the event + * @param displayId + * @hide + */ + public abstract void setDisplayId(int displayId); + /** * Copies the event. * * @return A deep copy of the event. diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 35546f8bf186..2c00391e7450 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.Display.INVALID_DISPLAY; + import android.annotation.NonNull; import android.annotation.TestApi; import android.os.Parcel; @@ -1246,6 +1248,7 @@ public class KeyEvent extends InputEvent implements Parcelable { private int mDeviceId; private int mSource; + private int mDisplayId; private int mMetaState; private int mAction; private int mKeyCode; @@ -1473,6 +1476,7 @@ public class KeyEvent extends InputEvent implements Parcelable { mScanCode = scancode; mFlags = flags; mSource = source; + mDisplayId = INVALID_DISPLAY; } /** @@ -1497,6 +1501,7 @@ public class KeyEvent extends InputEvent implements Parcelable { mDeviceId = deviceId; mFlags = flags; mSource = InputDevice.SOURCE_KEYBOARD; + mDisplayId = INVALID_DISPLAY; } /** @@ -1511,6 +1516,7 @@ public class KeyEvent extends InputEvent implements Parcelable { mMetaState = origEvent.mMetaState; mDeviceId = origEvent.mDeviceId; mSource = origEvent.mSource; + mDisplayId = origEvent.mDisplayId; mScanCode = origEvent.mScanCode; mFlags = origEvent.mFlags; mCharacters = origEvent.mCharacters; @@ -1537,6 +1543,7 @@ public class KeyEvent extends InputEvent implements Parcelable { mMetaState = origEvent.mMetaState; mDeviceId = origEvent.mDeviceId; mSource = origEvent.mSource; + mDisplayId = origEvent.mDisplayId; mScanCode = origEvent.mScanCode; mFlags = origEvent.mFlags; mCharacters = origEvent.mCharacters; @@ -1564,7 +1571,7 @@ public class KeyEvent extends InputEvent implements Parcelable { */ public static KeyEvent obtain(long downTime, long eventTime, int action, int code, int repeat, int metaState, - int deviceId, int scancode, int flags, int source, String characters) { + int deviceId, int scancode, int flags, int source, int displayId, String characters) { KeyEvent ev = obtain(); ev.mDownTime = downTime; ev.mEventTime = eventTime; @@ -1576,11 +1583,26 @@ public class KeyEvent extends InputEvent implements Parcelable { ev.mScanCode = scancode; ev.mFlags = flags; ev.mSource = source; + ev.mDisplayId = displayId; ev.mCharacters = characters; return ev; } /** + * Obtains a (potentially recycled) key event. + * + * @hide + */ + public static KeyEvent obtain(long downTime, long eventTime, int action, + int code, int repeat, int metaState, + int deviceId, int scancode, int flags, int source, String characters) { + return obtain(downTime, eventTime, action, code, repeat, metaState, deviceId, scancode, + flags, source, INVALID_DISPLAY, characters); + } + + /** + + /** * Obtains a (potentially recycled) copy of another key event. * * @hide @@ -1597,6 +1619,7 @@ public class KeyEvent extends InputEvent implements Parcelable { ev.mScanCode = other.mScanCode; ev.mFlags = other.mFlags; ev.mSource = other.mSource; + ev.mDisplayId = other.mDisplayId; ev.mCharacters = other.mCharacters; return ev; } @@ -1683,6 +1706,7 @@ public class KeyEvent extends InputEvent implements Parcelable { mMetaState = origEvent.mMetaState; mDeviceId = origEvent.mDeviceId; mSource = origEvent.mSource; + mDisplayId = origEvent.mDisplayId; mScanCode = origEvent.mScanCode; mFlags = origEvent.mFlags; // Don't copy mCharacters, since one way or the other we'll lose it @@ -1917,6 +1941,18 @@ public class KeyEvent extends InputEvent implements Parcelable { mSource = source; } + /** @hide */ + @Override + public final int getDisplayId() { + return mDisplayId; + } + + /** @hide */ + @Override + public final void setDisplayId(int displayId) { + mDisplayId = displayId; + } + /** * <p>Returns the state of the meta keys.</p> * @@ -2852,6 +2888,7 @@ public class KeyEvent extends InputEvent implements Parcelable { msg.append(", downTime=").append(mDownTime); msg.append(", deviceId=").append(mDeviceId); msg.append(", source=0x").append(Integer.toHexString(mSource)); + msg.append(", displayId=").append(mDisplayId); msg.append(" }"); return msg.toString(); } @@ -2983,6 +3020,7 @@ public class KeyEvent extends InputEvent implements Parcelable { private KeyEvent(Parcel in) { mDeviceId = in.readInt(); mSource = in.readInt(); + mDisplayId = in.readInt(); mAction = in.readInt(); mKeyCode = in.readInt(); mRepeatCount = in.readInt(); @@ -2999,6 +3037,7 @@ public class KeyEvent extends InputEvent implements Parcelable { out.writeInt(mDeviceId); out.writeInt(mSource); + out.writeInt(mDisplayId); out.writeInt(mAction); out.writeInt(mKeyCode); out.writeInt(mRepeatCount); diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 9148c27f6006..344806aa4d50 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -1943,11 +1943,13 @@ public final class MotionEvent extends InputEvent implements Parcelable { } /** @hide */ + @Override public int getDisplayId() { return nativeGetDisplayId(mNativePtr); } /** @hide */ + @Override public void setDisplayId(int displayId) { nativeSetDisplayId(mNativePtr, displayId); } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index e10eeb0457be..e0df59f57b31 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Matrix; @@ -29,6 +30,9 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * <p>A display list records a series of graphics related operations and can replay * them later. Display lists are usually built by recording operations on a @@ -449,6 +453,25 @@ public class RenderNode { return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering); } + /** @hide */ + @IntDef({USAGE_BACKGROUND}) + @Retention(RetentionPolicy.SOURCE) + public @interface UsageHint {} + + /** The default usage hint */ + public static final int USAGE_UNKNOWN = 0; + + /** Usage is background content */ + public static final int USAGE_BACKGROUND = 1; + + /** + * Provides a hint on what this RenderNode's display list content contains. This hint is used + * for automatic content transforms to improve accessibility or similar. + */ + public void setUsageHint(@UsageHint int usageHint) { + nSetUsageHint(mNativeRenderNode, usageHint); + } + /** * Indicates whether the content of this display list overlaps. * @@ -948,6 +971,8 @@ public class RenderNode { private static native boolean nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering); @CriticalNative + private static native void nSetUsageHint(long renderNode, int usageHint); + @CriticalNative private static native boolean nSetElevation(long renderNode, float lift); @CriticalNative private static native boolean nSetTranslationX(long renderNode, float translationX); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 546ea87e23a2..19e95b85e61f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -20442,6 +20442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { if (renderNode == null) { renderNode = RenderNode.create(drawable.getClass().getName(), this); + renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); } final Rect bounds = drawable.getBounds(); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 4d7b73cb7c08..8c7ac731b3e3 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -1692,6 +1692,15 @@ public interface WindowManager extends ViewManager { public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000; /** + * Flag to indicate that the status bar window is now in an explicit expanded state, meaning + * that status bar will not be hidden by any window with flag {@link #FLAG_FULLSCREEN} or + * {@link View#SYSTEM_UI_FLAG_FULLSCREEN} set. + * This can only be set by {@link LayoutParams#TYPE_STATUS_BAR}. + * @hide + */ + public static final int PRIVATE_FLAG_STATUS_BAR_EXPANDED = 0x00800000; + + /** * Control flags that are private to the platform. * @hide */ @@ -1779,7 +1788,11 @@ public interface WindowManager extends ViewManager { @ViewDebug.FlagToString( mask = PRIVATE_FLAG_IS_SCREEN_DECOR, equals = PRIVATE_FLAG_IS_SCREEN_DECOR, - name = "IS_SCREEN_DECOR") + name = "IS_SCREEN_DECOR"), + @ViewDebug.FlagToString( + mask = PRIVATE_FLAG_STATUS_BAR_EXPANDED, + equals = PRIVATE_FLAG_STATUS_BAR_EXPANDED, + name = "STATUS_BAR_EXPANDED") }) @TestApi public int privateFlags; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9a6006526cf7..2e7ef8b4e28a 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3451,7 +3451,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ColorStateList mTextColor = null; ColorStateList mTextColorHint = null; ColorStateList mTextColorLink = null; - int mTextSize = 0; + int mTextSize = -1; String mFontFamily = null; Typeface mFontTypeface = null; boolean mFontFamilyExplicit = false; @@ -3662,7 +3662,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener setHighlightColor(attributes.mTextColorHighlight); } - if (attributes.mTextSize != 0) { + if (attributes.mTextSize != -1) { setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */); } diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index 0ed972477123..768dddd35a6d 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -33,7 +33,7 @@ interface IAppOpsService { void stopWatchingMode(IAppOpsCallback callback); IBinder getToken(IBinder clientToken); int permissionToOpCode(String permission); - int noteProxyOperation(int code, String proxyPackageName, + int noteProxyOperation(int code, int proxyUid, String proxyPackageName, int callingUid, String callingPackageName); // Remaining methods are only used in Java. diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java new file mode 100644 index 000000000000..e5d6556e1218 --- /dev/null +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.app.procstats; + + +import android.os.Parcel; +import android.os.SystemClock; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Slog; +import android.util.TimeUtils; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Objects; + +public final class AssociationState { + private static final String TAG = "ProcessStats"; + private static final boolean DEBUG = false; + + private final ProcessStats mProcessStats; + private final ProcessStats.PackageState mPackageState; + private final String mProcessName; + private final String mName; + private final DurationsTable mDurations; + + public final class SourceState { + final SourceKey mKey; + int mProcStateSeq = -1; + int mProcState = ProcessStats.STATE_NOTHING; + boolean mInTrackingList; + int mNesting; + int mCount; + long mStartUptime; + long mDuration; + long mTrackingUptime; + int mActiveCount; + long mActiveStartUptime; + long mActiveDuration; + + SourceState(SourceKey key) { + mKey = key; + } + + public AssociationState getAssociationState() { + return AssociationState.this; + } + + public String getProcessName() { + return mKey.mProcess; + } + + public int getUid() { + return mKey.mUid; + } + + public void trackProcState(int procState, int seq, long now) { + procState = ProcessState.PROCESS_STATE_TO_STATE[procState]; + if (seq != mProcStateSeq) { + mProcStateSeq = seq; + mProcState = procState; + } else if (procState < mProcState) { + mProcState = procState; + } + if (procState < ProcessStats.STATE_HOME) { + if (!mInTrackingList) { + mInTrackingList = true; + mTrackingUptime = now; + mProcessStats.mTrackingAssociations.add(this); + } + } else { + stopTracking(now); + } + } + + public void stop() { + mNesting--; + if (mNesting == 0) { + mDuration += SystemClock.uptimeMillis() - mStartUptime; + mNumActive--; + stopTracking(SystemClock.uptimeMillis()); + } + } + + void startActive(long now) { + if (mInTrackingList) { + if (mActiveStartUptime == 0) { + mActiveStartUptime = now; + mActiveCount++; + } + } else { + Slog.wtf(TAG, "startActive while not tracking: " + this); + } + } + + void stopActive(long now) { + if (mActiveStartUptime != 0) { + if (!mInTrackingList) { + Slog.wtf(TAG, "stopActive while not tracking: " + this); + } + mActiveDuration += now - mActiveStartUptime; + mActiveStartUptime = 0; + } + } + + void stopTracking(long now) { + stopActive(now); + if (mInTrackingList) { + mInTrackingList = false; + // Do a manual search for where to remove, since these objects will typically + // be towards the end of the array. + final ArrayList<SourceState> list = mProcessStats.mTrackingAssociations; + for (int i = list.size() - 1; i >= 0; i--) { + if (list.get(i) == this) { + list.remove(i); + return; + } + } + Slog.wtf(TAG, "Stop tracking didn't find in tracking list: " + this); + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(64); + sb.append("SourceState{").append(Integer.toHexString(System.identityHashCode(this))) + .append(" ").append(mKey.mProcess).append("/").append(mKey.mUid); + if (mProcState != ProcessStats.STATE_NOTHING) { + sb.append(" ").append(DumpUtils.STATE_NAMES[mProcState]).append(" #") + .append(mProcStateSeq); + } + sb.append("}"); + return sb.toString(); + } + } + + private final static class SourceKey { + /** + * UID, consider this final. Not final just to avoid a temporary object during lookup. + */ + int mUid; + + /** + * Process name, consider this final. Not final just to avoid a temporary object during + * lookup. + */ + String mProcess; + + SourceKey(int uid, String process) { + mUid = uid; + mProcess = process; + } + + public boolean equals(Object o) { + if (!(o instanceof SourceKey)) { + return false; + } + SourceKey s = (SourceKey) o; + return s.mUid == mUid && Objects.equals(s.mProcess, mProcess); + } + + @Override + public int hashCode() { + return Integer.hashCode(mUid) ^ (mProcess == null ? 0 : mProcess.hashCode()); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(64); + sb.append("SourceKey{"); + UserHandle.formatUid(sb, mUid); + sb.append(' '); + sb.append(mProcess); + sb.append('}'); + return sb.toString(); + } + } + + /** + * All known sources for this target component... uid -> process name -> source state. + */ + private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>(); + + private final SourceKey mTmpSourceKey = new SourceKey(0, null); + + private ProcessState mProc; + + private int mNumActive; + + public AssociationState(ProcessStats processStats, ProcessStats.PackageState packageState, + String name, String processName, ProcessState proc) { + mProcessStats = processStats; + mPackageState = packageState; + mName = name; + mProcessName = processName; + mDurations = new DurationsTable(processStats.mTableData); + mProc = proc; + } + + public int getUid() { + return mPackageState.mUid; + } + + public String getPackage() { + return mPackageState.mPackageName; + } + + public String getProcessName() { + return mProcessName; + } + + public String getName() { + return mName; + } + + public ProcessState getProcess() { + return mProc; + } + + public void setProcess(ProcessState proc) { + mProc = proc; + } + + public SourceState startSource(int uid, String processName) { + mTmpSourceKey.mUid = uid; + mTmpSourceKey.mProcess = processName; + SourceState src = mSources.get(mTmpSourceKey); + if (src == null) { + SourceKey key = new SourceKey(uid, processName); + src = new SourceState(key); + mSources.put(key, src); + } + src.mNesting++; + if (src.mNesting == 1) { + src.mCount++; + src.mStartUptime = SystemClock.uptimeMillis(); + mNumActive++; + } + return src; + } + + public void add(AssociationState other) { + mDurations.addDurations(other.mDurations); + for (int isrc = other.mSources.size() - 1; isrc >= 0; isrc--) { + final SourceKey key = other.mSources.keyAt(isrc); + final SourceState otherSrc = other.mSources.valueAt(isrc); + SourceState mySrc = mSources.get(key); + if (mySrc == null) { + mySrc = new SourceState(key); + mSources.put(key, mySrc); + } + mySrc.mCount += otherSrc.mCount; + mySrc.mDuration += otherSrc.mDuration; + mySrc.mActiveCount += otherSrc.mActiveCount; + mySrc.mActiveDuration += otherSrc.mActiveDuration; + } + } + + public boolean isInUse() { + return mNumActive > 0; + } + + public void resetSafely(long now) { + mDurations.resetTable(); + if (!isInUse()) { + mSources.clear(); + } else { + // We have some active sources... clear out everything but those. + for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { + SourceState src = mSources.valueAt(isrc); + if (src.mNesting > 0) { + src.mCount = 1; + src.mStartUptime = now; + src.mDuration = 0; + if (src.mActiveStartUptime > 0) { + src.mActiveCount = 1; + src.mActiveStartUptime = now; + } else { + src.mActiveCount = 0; + } + src.mActiveDuration = 0; + } else { + mSources.removeAt(isrc); + } + } + } + } + + public void writeToParcel(ProcessStats stats, Parcel out, long nowUptime) { + mDurations.writeToParcel(out); + final int NSRC = mSources.size(); + out.writeInt(NSRC); + for (int isrc = 0; isrc < NSRC; isrc++) { + final SourceKey key = mSources.keyAt(isrc); + final SourceState src = mSources.valueAt(isrc); + out.writeInt(key.mUid); + stats.writeCommonString(out, key.mProcess); + out.writeInt(src.mCount); + out.writeLong(src.mDuration); + out.writeInt(src.mActiveCount); + out.writeLong(src.mActiveDuration); + } + } + + /** + * Returns non-null if all else fine, else a String that describes the error that + * caused it to fail. + */ + public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) { + if (!mDurations.readFromParcel(in)) { + return "Duration table corrupt"; + } + final int NSRC = in.readInt(); + if (NSRC < 0 || NSRC > 100000) { + return "Association with bad src count: " + NSRC; + } + for (int isrc = 0; isrc < NSRC; isrc++) { + final int uid = in.readInt(); + final String procName = stats.readCommonString(in, parcelVersion); + final SourceKey key = new SourceKey(uid, procName); + final SourceState src = new SourceState(key); + src.mCount = in.readInt(); + src.mDuration = in.readLong(); + src.mActiveCount = in.readInt(); + src.mActiveDuration = in.readLong(); + mSources.put(key, src); + } + return null; + } + + public void commitStateTime(long nowUptime) { + if (isInUse()) { + for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) { + SourceState src = mSources.valueAt(isrc); + if (src.mNesting > 0) { + src.mDuration += nowUptime - src.mStartUptime; + src.mStartUptime = nowUptime; + } + if (src.mActiveStartUptime > 0) { + src.mActiveDuration += nowUptime - src.mActiveStartUptime; + src.mActiveStartUptime = nowUptime; + } + } + } + } + + public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, + long now, long totalTime, boolean dumpSummary, boolean dumpAll) { + if (dumpAll) { + pw.print(prefix); + pw.print("mNumActive="); + pw.println(mNumActive); + } + final int NSRC = mSources.size(); + for (int isrc = 0; isrc < NSRC; isrc++) { + final SourceKey key = mSources.keyAt(isrc); + final SourceState src = mSources.valueAt(isrc); + pw.print(prefixInner); + pw.print("<- "); + pw.print(key.mProcess); + pw.print(" / "); + UserHandle.formatUid(pw, key.mUid); + pw.println(":"); + pw.print(prefixInner); + pw.print(" Count "); + pw.print(src.mCount); + long duration = src.mDuration; + if (src.mNesting > 0) { + duration += now - src.mStartUptime; + } + if (dumpAll) { + pw.print(" / Duration "); + TimeUtils.formatDuration(duration, pw); + pw.print(" / "); + } else { + pw.print(" / time "); + } + DumpUtils.printPercent(pw, (double)duration/(double)totalTime); + if (src.mNesting > 0) { + pw.print(" (running"); + if (src.mProcState != ProcessStats.STATE_NOTHING) { + pw.print(" / "); + pw.print(DumpUtils.STATE_NAMES[src.mProcState]); + pw.print(" #"); + pw.print(src.mProcStateSeq); + } + pw.print(")"); + } + pw.println(); + if (src.mActiveCount > 0) { + pw.print(prefixInner); + pw.print(" Active count "); + pw.print(src.mActiveCount); + duration = src.mActiveDuration; + if (src.mActiveStartUptime > 0) { + duration += now - src.mActiveStartUptime; + } + if (dumpAll) { + pw.print(" / Duration "); + TimeUtils.formatDuration(duration, pw); + pw.print(" / "); + } else { + pw.print(" / time "); + } + DumpUtils.printPercent(pw, (double)duration/(double)totalTime); + if (src.mActiveStartUptime > 0) { + pw.print(" (running)"); + } + pw.println(); + } + } + } + + public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers, + String associationName, long now) { + final int NSRC = mSources.size(); + for (int isrc = 0; isrc < NSRC; isrc++) { + final SourceKey key = mSources.keyAt(isrc); + final SourceState src = mSources.valueAt(isrc); + pw.print("pkgasc"); + pw.print(","); + pw.print(pkgName); + pw.print(","); + pw.print(uid); + pw.print(","); + pw.print(vers); + pw.print(","); + pw.print(associationName); + pw.print(","); + pw.print(key.mProcess); + pw.print(","); + pw.print(key.mUid); + pw.print(","); + pw.print(src.mCount); + long duration = src.mDuration; + if (src.mNesting > 0) { + duration += now - src.mStartUptime; + } + pw.print(","); + pw.print(duration); + pw.print(","); + pw.print(src.mActiveCount); + duration = src.mActiveDuration; + if (src.mActiveStartUptime > 0) { + duration += now - src.mActiveStartUptime; + } + pw.print(","); + pw.print(duration); + pw.println(); + } + } + + public String toString() { + return "AssociationState{" + Integer.toHexString(System.identityHashCode(this)) + + " " + mName + " pkg=" + mPackageState.mPackageName + " proc=" + + Integer.toHexString(System.identityHashCode(mProc)) + "}"; + } +} diff --git a/core/java/com/android/internal/app/procstats/DumpUtils.java b/core/java/com/android/internal/app/procstats/DumpUtils.java index e38a844fe8fe..06b6552ca59f 100644 --- a/core/java/com/android/internal/app/procstats/DumpUtils.java +++ b/core/java/com/android/internal/app/procstats/DumpUtils.java @@ -362,12 +362,13 @@ public final class DumpUtils { } } - public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix, + public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header, ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime) { for (int i=procs.size()-1; i>=0; i--) { final ProcessState proc = procs.get(i); - proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime); + proc.dumpSummary(pw, prefix, header, screenStates, memStates, procStates, now, + totalTime); } } diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java index 65bd48f99cbd..dbf7c93dadd2 100644 --- a/core/java/com/android/internal/app/procstats/ProcessState.java +++ b/core/java/com/android/internal/app/procstats/ProcessState.java @@ -71,7 +71,7 @@ public final class ProcessState { private static final boolean DEBUG_PARCEL = false; // Map from process states to the states we track. - private static final int[] PROCESS_STATE_TO_STATE = new int[] { + static final int[] PROCESS_STATE_TO_STATE = new int[] { STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT STATE_PERSISTENT, // ActivityManager.PROCESS_STATE_PERSISTENT_UI STATE_TOP, // ActivityManager.PROCESS_STATE_TOP @@ -378,6 +378,10 @@ public final class ProcessState { } } + public int getState() { + return mCurState; + } + public void commitStateTime(long now) { if (mCurState != STATE_NOTHING) { long dur = now - mStartTime; @@ -580,7 +584,7 @@ public final class ProcessState { ProcessStateHolder holder = pkgList.valueAt(index); ProcessState proc = holder.state; if (mDead && proc.mCommonProcess != proc) { - // Somehow we are contining to use a process state that is dead, because + // Somehow we are continuing to use a process state that is dead, because // it was not being told it was active during the last commit. We can recover // from this by generating a fresh new state, but this is bad because we // are losing whatever data we had in the old process state. @@ -600,17 +604,17 @@ public final class ProcessState { + pkgList.keyAt(index) + "/" + proc.mUid + " for multi-proc " + proc.mName); } - PackageState pkg = vpkg.get(proc.mVersion); - if (pkg == null) { + PackageState expkg = vpkg.get(proc.mVersion); + if (expkg == null) { throw new IllegalStateException("No existing package " + pkgList.keyAt(index) + "/" + proc.mUid + " for multi-proc " + proc.mName + " version " + proc.mVersion); } String savedName = proc.mName; - proc = pkg.mProcesses.get(proc.mName); + proc = expkg.mProcesses.get(proc.mName); if (proc == null) { throw new IllegalStateException("Didn't create per-package process " - + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid); + + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid); } holder.state = proc; } @@ -769,11 +773,14 @@ public final class ProcessState { return totalTime; } - public void dumpSummary(PrintWriter pw, String prefix, + public void dumpSummary(PrintWriter pw, String prefix, String header, int[] screenStates, int[] memStates, int[] procStates, long now, long totalTime) { pw.print(prefix); pw.print("* "); + if (header != null) { + pw.print(header); + } pw.print(mName); pw.print(" / "); UserHandle.formatUid(pw, mUid); diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index d35bdddb3c57..3cafa5e5ec20 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -16,6 +16,7 @@ package com.android.internal.app.procstats; +import android.content.ComponentName; import android.os.Debug; import android.os.Parcel; import android.os.Parcelable; @@ -157,7 +158,7 @@ public final class ProcessStats implements Parcelable { }; // Current version of the parcel format. - private static final int PARCEL_VERSION = 27; + private static final int PARCEL_VERSION = 32; // In-memory Parcel magic number, used to detect attempts to unmarshall bad data private static final int MAGIC = 0x50535454; @@ -168,6 +169,8 @@ public final class ProcessStats implements Parcelable { public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>(); public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>(); + public final ArrayList<AssociationState.SourceState> mTrackingAssociations = new ArrayList<>(); + public final long[] mMemFactorDurations = new long[ADJ_COUNT]; public int mMemFactor = STATE_NOTHING; public long mStartTime; @@ -250,6 +253,7 @@ public final class ProcessStats implements Parcelable { final PackageState otherState = versions.valueAt(iv); final int NPROCS = otherState.mProcesses.size(); final int NSRVS = otherState.mServices.size(); + final int NASCS = otherState.mAssociations.size(); for (int iproc=0; iproc<NPROCS; iproc++) { ProcessState otherProc = otherState.mProcesses.valueAt(iproc); if (otherProc.getCommonProcess() != otherProc) { @@ -277,6 +281,14 @@ public final class ProcessStats implements Parcelable { otherSvc.getProcessName(), otherSvc.getName()); thisSvc.add(otherSvc); } + for (int iasc=0; iasc<NASCS; iasc++) { + AssociationState otherAsc = otherState.mAssociations.valueAt(iasc); + if (DEBUG) Slog.d(TAG, "Adding pkg " + pkgName + " uid " + uid + + " association " + otherAsc.getName()); + AssociationState thisAsc = getAssociationStateLocked(pkgName, uid, vers, + otherAsc.getProcessName(), otherAsc.getName()); + thisAsc.add(otherAsc); + } } } } @@ -478,7 +490,16 @@ public final class ProcessStats implements Parcelable { pkgState.mServices.removeAt(isvc); } } - if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0) { + for (int iasc=pkgState.mAssociations.size()-1; iasc>=0; iasc--) { + final AssociationState as = pkgState.mAssociations.valueAt(iasc); + if (as.isInUse()) { + as.resetSafely(now); + } else { + pkgState.mAssociations.removeAt(iasc); + } + } + if (pkgState.mProcesses.size() <= 0 && pkgState.mServices.size() <= 0 + && pkgState.mAssociations.size() <= 0) { vpkgs.removeAt(iv); } } @@ -708,7 +729,7 @@ public final class ProcessStats implements Parcelable { } } - private void writeCommonString(Parcel out, String name) { + void writeCommonString(Parcel out, String name) { Integer index = mCommonStringToIndex.get(name); if (index != null) { out.writeInt(index); @@ -720,7 +741,7 @@ public final class ProcessStats implements Parcelable { out.writeString(name); } - private String readCommonString(Parcel in, int version) { + String readCommonString(Parcel in, int version) { if (version <= 9) { return in.readString(); } @@ -791,6 +812,10 @@ public final class ProcessStats implements Parcelable { for (int isvc=0; isvc<NSRVS; isvc++) { pkgState.mServices.valueAt(isvc).commitStateTime(now); } + final int NASCS = pkgState.mAssociations.size(); + for (int iasc=0; iasc<NASCS; iasc++) { + pkgState.mAssociations.valueAt(iasc).commitStateTime(now); + } } } } @@ -874,6 +899,14 @@ public final class ProcessStats implements Parcelable { writeCommonString(out, svc.getProcessName()); svc.writeToParcel(out, now); } + final int NASCS = pkgState.mAssociations.size(); + out.writeInt(NASCS); + for (int iasc=0; iasc<NASCS; iasc++) { + writeCommonString(out, pkgState.mAssociations.keyAt(iasc)); + final AssociationState asc = pkgState.mAssociations.valueAt(iasc); + writeCommonString(out, asc.getProcessName()); + asc.writeToParcel(this, out, now); + } } } } @@ -1078,7 +1111,7 @@ public final class ProcessStats implements Parcelable { while (NVERS > 0) { NVERS--; final long vers = in.readLong(); - PackageState pkgState = new PackageState(pkgName, uid); + PackageState pkgState = new PackageState(this, pkgName, uid, vers); LongSparseArray<PackageState> vpkg = mPackages.get(pkgName, uid); if (vpkg == null) { vpkg = new LongSparseArray<>(); @@ -1157,6 +1190,34 @@ public final class ProcessStats implements Parcelable { + serviceName + " " + uid + " " + serv); pkgState.mServices.put(serviceName, serv); } + int NASCS = in.readInt(); + if (NASCS < 0) { + mReadError = "bad package association count: " + NASCS; + return; + } + while (NASCS > 0) { + NASCS--; + String associationName = readCommonString(in, version); + if (associationName == null) { + mReadError = "bad package association name"; + return; + } + String processName = readCommonString(in, version); + AssociationState asc = hadData + ? pkgState.mAssociations.get(associationName) : null; + if (asc == null) { + asc = new AssociationState(this, pkgState, associationName, + processName, null); + } + String errorMsg = asc.readFromParcel(this, in, version); + if (errorMsg != null) { + mReadError = errorMsg; + return; + } + if (DEBUG_PARCEL) Slog.d(TAG, "Adding package " + pkgName + " association: " + + associationName + " " + uid + " " + asc); + pkgState.mAssociations.put(associationName, asc); + } } } } @@ -1183,33 +1244,38 @@ public final class ProcessStats implements Parcelable { public PackageState getPackageStateLocked(String packageName, int uid, long vers) { LongSparseArray<PackageState> vpkg = mPackages.get(packageName, uid); if (vpkg == null) { - vpkg = new LongSparseArray<PackageState>(); + vpkg = new LongSparseArray<>(); mPackages.put(packageName, uid, vpkg); } PackageState as = vpkg.get(vers); if (as != null) { return as; } - as = new PackageState(packageName, uid); + as = new PackageState(this, packageName, uid, vers); vpkg.put(vers, as); return as; } public ProcessState getProcessStateLocked(String packageName, int uid, long vers, String processName) { - final PackageState pkgState = getPackageStateLocked(packageName, uid, vers); + return getProcessStateLocked(getPackageStateLocked(packageName, uid, vers), processName); + } + + public ProcessState getProcessStateLocked(PackageState pkgState, String processName) { ProcessState ps = pkgState.mProcesses.get(processName); if (ps != null) { return ps; } - ProcessState commonProc = mProcesses.get(processName, uid); + ProcessState commonProc = mProcesses.get(processName, pkgState.mUid); if (commonProc == null) { - commonProc = new ProcessState(this, packageName, uid, vers, processName); - mProcesses.put(processName, uid, commonProc); + commonProc = new ProcessState(this, pkgState.mPackageName, pkgState.mUid, + pkgState.mVersionCode, processName); + mProcesses.put(processName, pkgState.mUid, commonProc); if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc); } if (!commonProc.isMultiPackage()) { - if (packageName.equals(commonProc.getPackage()) && vers == commonProc.getVersion()) { + if (pkgState.mPackageName.equals(commonProc.getPackage()) + && pkgState.mVersionCode == commonProc.getVersion()) { // This common process is not in use by multiple packages, and // is for the calling package, so we can just use it directly. ps = commonProc; @@ -1228,7 +1294,7 @@ public final class ProcessStats implements Parcelable { // First let's make a copy of the current process state and put // that under the now unique state for its original package name. final PackageState commonPkgState = getPackageStateLocked(commonProc.getPackage(), - uid, commonProc.getVersion()); + pkgState.mUid, commonProc.getVersion()); if (commonPkgState != null) { ProcessState cloned = commonProc.clone(now); if (DEBUG) Slog.d(TAG, "GETPROC setting clone to pkg " + commonProc.getPackage() @@ -1245,18 +1311,31 @@ public final class ProcessStats implements Parcelable { Slog.d(TAG, "GETPROC leaving proc of " + ss); } } + // Also update active associations. + for (int i=commonPkgState.mAssociations.size()-1; i>=0; i--) { + AssociationState as = commonPkgState.mAssociations.valueAt(i); + if (as.getProcess() == commonProc) { + if (DEBUG) Slog.d(TAG, "GETPROC switching association to cloned: " + + as); + as.setProcess(cloned); + } else if (DEBUG) { + Slog.d(TAG, "GETPROC leaving proc of " + as); + } + } } else { Slog.w(TAG, "Cloning proc state: no package state " + commonProc.getPackage() - + "/" + uid + " for proc " + commonProc.getName()); + + "/" + pkgState.mUid + " for proc " + commonProc.getName()); } // And now make a fresh new process state for the new package name. - ps = new ProcessState(commonProc, packageName, uid, vers, processName, now); + ps = new ProcessState(commonProc, pkgState.mPackageName, pkgState.mUid, + pkgState.mVersionCode, processName, now); if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); } } else { // The common process is for multiple packages, we need to create a // separate object for the per-package data. - ps = new ProcessState(commonProc, packageName, uid, vers, processName, + ps = new ProcessState(commonProc, pkgState.mPackageName, pkgState.mUid, + pkgState.mVersionCode, processName, SystemClock.uptimeMillis()); if (DEBUG) Slog.d(TAG, "GETPROC created new pkg " + ps); } @@ -1281,6 +1360,51 @@ public final class ProcessStats implements Parcelable { return ss; } + public AssociationState getAssociationStateLocked(String packageName, int uid, long vers, + String processName, String className) { + final ProcessStats.PackageState pkgs = getPackageStateLocked(packageName, uid, vers); + AssociationState as = pkgs.mAssociations.get(className); + if (as != null) { + if (DEBUG) Slog.d(TAG, "GETASC: returning existing " + as); + return as; + } + final ProcessState procs = processName != null + ? getProcessStateLocked(packageName, uid, vers, processName) : null; + as = new AssociationState(this, pkgs, className, processName, procs); + pkgs.mAssociations.put(className, as); + if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + procs); + return as; + } + + public void updateTrackingAssociationsLocked(int curSeq, long now) { + final int NUM = mTrackingAssociations.size(); + for (int i = NUM - 1; i >= 0; i--) { + final AssociationState.SourceState act = mTrackingAssociations.get(i); + if (act.mProcStateSeq != curSeq) { + act.mInTrackingList = false; + act.mProcState = STATE_NOTHING; + mTrackingAssociations.remove(i); + } else { + final ProcessState proc = act.getAssociationState().getProcess(); + if (proc != null) { + if (act.mProcState == proc.getState()) { + act.startActive(now); + } else { + act.stopActive(now); + if (act.mProcState < proc.getState()) { + Slog.w(TAG, "Tracking association " + act + " whose proc state " + + act.mProcState + " is better than process " + proc + + " proc state " + proc.getState()); + } + } + } else { + Slog.wtf(TAG, "Tracking association without process: " + act + + " in " + act.getAssociationState()); + } + } + } + } + public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary, boolean dumpAll, boolean activeOnly) { long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, @@ -1304,6 +1428,7 @@ public final class ProcessStats implements Parcelable { final PackageState pkgState = vpkgs.valueAt(iv); final int NPROCS = pkgState.mProcesses.size(); final int NSRVS = pkgState.mServices.size(); + final int NASCS = pkgState.mAssociations.size(); final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); if (!pkgMatch) { boolean procMatch = false; @@ -1318,7 +1443,7 @@ public final class ProcessStats implements Parcelable { continue; } } - if (NPROCS > 0 || NSRVS > 0) { + if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { if (!printedHeader) { if (sepNeeded) pw.println(); pw.println("Per-Package Stats:"); @@ -1368,7 +1493,7 @@ public final class ProcessStats implements Parcelable { } procs.add(proc); } - DumpUtils.dumpProcessSummaryLocked(pw, " ", procs, + DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs, ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES, now, totalTime); } @@ -1378,14 +1503,14 @@ public final class ProcessStats implements Parcelable { continue; } if (activeOnly && !svc.isInUse()) { - pw.print(" (Not active: "); + pw.print(" (Not active service: "); pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")"); continue; } if (dumpAll) { pw.print(" Service "); } else { - pw.print(" * "); + pw.print(" * Svc "); } pw.print(pkgState.mServices.keyAt(isvc)); pw.println(":"); @@ -1393,6 +1518,27 @@ public final class ProcessStats implements Parcelable { svc.dumpStats(pw, " ", " ", " ", now, totalTime, dumpSummary, dumpAll); } + for (int iasc=0; iasc<NASCS; iasc++) { + AssociationState asc = pkgState.mAssociations.valueAt(iasc); + if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { + continue; + } + if (activeOnly && !asc.isInUse()) { + pw.print(" (Not active association: "); + pw.print(pkgState.mAssociations.keyAt(iasc)); pw.println(")"); + continue; + } + if (dumpAll) { + pw.print(" Association "); + } else { + pw.print(" * Asc "); + } + pw.print(pkgState.mAssociations.keyAt(iasc)); + pw.println(":"); + pw.print(" Process: "); pw.println(asc.getProcessName()); + asc.dumpStats(pw, " ", " ", " ", + now, totalTime, dumpSummary, dumpAll); + } } } } @@ -1440,17 +1586,77 @@ public final class ProcessStats implements Parcelable { proc.dumpInternalLocked(pw, " ", dumpAll); } } + if (dumpAll) { - pw.println(); + if (sepNeeded) { + pw.println(); + } + sepNeeded = true; pw.print(" Total procs: "); pw.print(numShownProcs); pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total"); + if (mTrackingAssociations.size() > 0) { + pw.println(); + pw.println("Tracking associations:"); + for (int i = 0; i < mTrackingAssociations.size(); i++) { + final AssociationState.SourceState src = mTrackingAssociations.get(i); + final AssociationState asc = src.getAssociationState(); + pw.print(" #"); + pw.print(i); + pw.print(": "); + pw.print(asc.getProcessName()); + pw.print("/"); + UserHandle.formatUid(pw, asc.getUid()); + pw.print(" <- "); + pw.print(src.getProcessName()); + pw.print("/"); + UserHandle.formatUid(pw, src.getUid()); + pw.println(":"); + pw.print(" Tracking for: "); + TimeUtils.formatDuration(now - src.mTrackingUptime, pw); + pw.println(); + pw.print(" Component: "); + pw.print(new ComponentName(asc.getPackage(), asc.getName()) + .flattenToShortString()); + pw.println(); + pw.print(" Proc state: "); + if (src.mProcState != ProcessStats.STATE_NOTHING) { + pw.print(DumpUtils.STATE_NAMES[src.mProcState]); + } else { + pw.print("--"); + } + pw.print(" #"); + pw.println(src.mProcStateSeq); + pw.print(" Process: "); + pw.println(asc.getProcess()); + if (src.mActiveCount > 0) { + pw.print(" Active count "); + pw.print(src.mActiveCount); + long duration = src.mActiveDuration; + if (src.mActiveStartUptime > 0) { + duration += now - src.mActiveStartUptime; + } + if (dumpAll) { + pw.print(" / Duration "); + TimeUtils.formatDuration(duration, pw); + pw.print(" / "); + } else { + pw.print(" / time "); + } + DumpUtils.printPercent(pw, (double)duration/(double)totalTime); + if (src.mActiveStartUptime > 0) { + pw.print(" (running)"); + } + pw.println(); + } + } + } } if (sepNeeded) { pw.println(); } if (dumpSummary) { - pw.println("Summary:"); + pw.println("Process summary:"); dumpSummaryLocked(pw, reqPackage, now, activeOnly); } else { dumpTotalsLocked(pw, now); @@ -1466,13 +1672,15 @@ public final class ProcessStats implements Parcelable { pw.print(" mRunning="); pw.println(mRunning); } - dumpFragmentationLocked(pw); + if (reqPackage == null) { + dumpFragmentationLocked(pw); + } } public void dumpSummaryLocked(PrintWriter pw, String reqPackage, long now, boolean activeOnly) { long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor, mStartTime, now); - dumpFilteredSummaryLocked(pw, null, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, + dumpFilteredSummaryLocked(pw, null, " ", null, ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, NON_CACHED_PROC_STATES, now, totalTime, reqPackage, activeOnly); pw.println(); dumpTotalsLocked(pw, now); @@ -1607,7 +1815,7 @@ public final class ProcessStats implements Parcelable { pw.println(); } - void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix, + void dumpFilteredSummaryLocked(PrintWriter pw, String header, String prefix, String prcLabel, int[] screenStates, int[] memStates, int[] procStates, int[] sortProcStates, long now, long totalTime, String reqPackage, boolean activeOnly) { ArrayList<ProcessState> procs = collectProcessesLocked(screenStates, memStates, @@ -1617,7 +1825,7 @@ public final class ProcessStats implements Parcelable { pw.println(); pw.println(header); } - DumpUtils.dumpProcessSummaryLocked(pw, prefix, procs, screenStates, memStates, + DumpUtils.dumpProcessSummaryLocked(pw, prefix, prcLabel, procs, screenStates, memStates, sortProcStates, now, totalTime); } } @@ -1708,6 +1916,7 @@ public final class ProcessStats implements Parcelable { final PackageState pkgState = vpkgs.valueAt(iv); final int NPROCS = pkgState.mProcesses.size(); final int NSRVS = pkgState.mServices.size(); + final int NASCS = pkgState.mAssociations.size(); for (int iproc=0; iproc<NPROCS; iproc++) { ProcessState proc = pkgState.mProcesses.valueAt(iproc); proc.dumpPackageProcCheckin(pw, pkgName, uid, vers, @@ -1719,6 +1928,12 @@ public final class ProcessStats implements Parcelable { final ServiceState svc = pkgState.mServices.valueAt(isvc); svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now); } + for (int iasc=0; iasc<NASCS; iasc++) { + final String associationName = DumpUtils.collapseString(pkgName, + pkgState.mAssociations.keyAt(iasc)); + final AssociationState asc = pkgState.mAssociations.valueAt(iasc); + asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now); + } } } } @@ -1850,6 +2065,7 @@ public final class ProcessStats implements Parcelable { final public static class ProcessStateHolder { public final long appVersion; public ProcessState state; + public PackageState pkg; public ProcessStateHolder(long _appVersion) { appVersion = _appVersion; @@ -1857,16 +2073,35 @@ public final class ProcessStats implements Parcelable { } public static final class PackageState { - public final ArrayMap<String, ProcessState> mProcesses - = new ArrayMap<String, ProcessState>(); - public final ArrayMap<String, ServiceState> mServices - = new ArrayMap<String, ServiceState>(); + public final ProcessStats mProcessStats; + public final ArrayMap<String, ProcessState> mProcesses = new ArrayMap<>(); + public final ArrayMap<String, ServiceState> mServices = new ArrayMap<>(); + public final ArrayMap<String, AssociationState> mAssociations = new ArrayMap<>(); public final String mPackageName; public final int mUid; + public final long mVersionCode; - public PackageState(String packageName, int uid) { + public PackageState(ProcessStats procStats, String packageName, int uid, long versionCode) { + mProcessStats = procStats; mUid = uid; mPackageName = packageName; + mVersionCode = versionCode; + } + + public AssociationState getAssociationStateLocked(ProcessState proc, String className) { + AssociationState as = mAssociations.get(className); + if (as != null) { + if (DEBUG) Slog.d(TAG, "GETASC: returning existing " + as); + if (proc != null) { + as.setProcess(proc); + } + return as; + } + as = new AssociationState(mProcessStats, this, className, proc.getName(), + proc); + mAssociations.put(className, as); + if (DEBUG) Slog.d(TAG, "GETASC: creating " + as + " in " + proc.getName()); + return as; } } diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java index 650de2ea2b68..04e61e067f53 100644 --- a/core/java/com/android/internal/app/procstats/ServiceState.java +++ b/core/java/com/android/internal/app/procstats/ServiceState.java @@ -18,30 +18,13 @@ package com.android.internal.app.procstats; import android.os.Parcel; -import android.os.Parcelable; import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.text.format.DateFormat; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.DebugUtils; -import android.util.Log; import android.util.Slog; -import android.util.SparseArray; import android.util.TimeUtils; -import com.android.internal.app.procstats.ProcessStats; import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING; -import java.io.IOException; -import java.io.InputStream; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Objects; public final class ServiceState { private static final String TAG = "ProcessStats"; @@ -51,7 +34,8 @@ public final class ServiceState { public static final int SERVICE_STARTED = 1; public static final int SERVICE_BOUND = 2; public static final int SERVICE_EXEC = 3; - public static final int SERVICE_COUNT = 4; + public static final int SERVICE_FOREGROUND = 4; + public static final int SERVICE_COUNT = 5; private final String mPackage; private final String mProcessName; @@ -79,6 +63,10 @@ public final class ServiceState { private int mExecState = STATE_NOTHING; private long mExecStartTime; + private int mForegroundCount; + private int mForegroundState = STATE_NOTHING; + private long mForegroundStartTime; + public ServiceState(ProcessStats processStats, String pkg, String name, String processName, ProcessState proc) { mPackage = pkg; @@ -121,6 +109,9 @@ public final class ServiceState { if (mExecState != ProcessStats.STATE_NOTHING) { setExecuting(true, memFactor, now); } + if (mForegroundState != ProcessStats.STATE_NOTHING) { + setForeground(true, memFactor, now); + } } } @@ -133,7 +124,8 @@ public final class ServiceState { // There was already an old owner, reset this object for its // new owner. mOwner = newOwner; - if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) { + if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING + || mForegroundState != STATE_NOTHING) { long now = SystemClock.uptimeMillis(); if (mStarted) { if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner @@ -153,6 +145,12 @@ public final class ServiceState { + mPackage + " service=" + mName + " proc=" + mProc); setExecuting(false, 0, now); } + if (mForegroundState != STATE_NOTHING) { + if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner + + " from " + mOwner + " while foreground: pkg=" + + mPackage + " service=" + mName + " proc=" + mProc); + setForeground(false, 0, now); + } } } } @@ -161,7 +159,8 @@ public final class ServiceState { public void clearCurrentOwner(Object owner, boolean silently) { if (mOwner == owner) { mProc.decActiveServices(mName); - if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) { + if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING + || mForegroundState != STATE_NOTHING) { long now = SystemClock.uptimeMillis(); if (mStarted) { if (!silently) { @@ -187,6 +186,14 @@ public final class ServiceState { } setExecuting(false, 0, now); } + if (mForegroundState != STATE_NOTHING) { + if (!silently) { + Slog.wtfStack(TAG, "Service owner " + owner + + " cleared while foreground: pkg=" + mPackage + " service=" + + mName + " proc=" + mProc); + } + setForeground(false, 0, now); + } } mOwner = null; } @@ -206,6 +213,7 @@ public final class ServiceState { mStartedCount += other.mStartedCount; mBoundCount += other.mBoundCount; mExecCount += other.mExecCount; + mForegroundCount += other.mForegroundCount; } public void resetSafely(long now) { @@ -214,7 +222,9 @@ public final class ServiceState { mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0; mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0; mExecCount = mExecState != STATE_NOTHING ? 1 : 0; - mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now; + mForegroundCount = mForegroundState != STATE_NOTHING ? 1 : 0; + mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = + mForegroundStartTime = now; } public void writeToParcel(Parcel out, long now) { @@ -223,6 +233,7 @@ public final class ServiceState { out.writeInt(mStartedCount); out.writeInt(mBoundCount); out.writeInt(mExecCount); + out.writeInt(mForegroundCount); } public boolean readFromParcel(Parcel in) { @@ -233,6 +244,7 @@ public final class ServiceState { mStartedCount = in.readInt(); mBoundCount = in.readInt(); mExecCount = in.readInt(); + mForegroundCount = in.readInt(); return true; } @@ -257,11 +269,17 @@ public final class ServiceState { now - mExecStartTime); mExecStartTime = now; } + if (mForegroundState != STATE_NOTHING) { + mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT), + now - mForegroundStartTime); + mForegroundStartTime = now; + } } private void updateRunning(int memFactor, long now) { final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING - || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING; + || mExecState != STATE_NOTHING || mForegroundState != STATE_NOTHING) + ? memFactor : STATE_NOTHING; if (mRunState != state) { if (mRunState != STATE_NOTHING) { mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT), @@ -348,6 +366,24 @@ public final class ServiceState { } } + public void setForeground(boolean foreground, int memFactor, long now) { + if (mOwner == null) { + Slog.wtf(TAG, "Foregrounding service " + this + " without owner"); + } + final int state = foreground ? memFactor : STATE_NOTHING; + if (mForegroundState != state) { + if (mForegroundState != STATE_NOTHING) { + mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT), + now - mForegroundStartTime); + } else if (foreground) { + mForegroundCount++; + } + mForegroundState = state; + mForegroundStartTime = now; + updateRunning(memFactor, now); + } + } + public long getDuration(int opType, int curState, long startTime, int memFactor, long now) { int state = opType + (memFactor*SERVICE_COUNT); @@ -366,6 +402,9 @@ public final class ServiceState { dumpStats(pw, prefix, prefixInner, headerPrefix, "Started", mStartedCount, ServiceState.SERVICE_STARTED, mStartedState, mStartedStartTime, now, totalTime, !dumpSummary || dumpAll); + dumpStats(pw, prefix, prefixInner, headerPrefix, "Foreground", + mForegroundCount, ServiceState.SERVICE_FOREGROUND, mForegroundState, + mForegroundStartTime, now, totalTime, !dumpSummary || dumpAll); dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound", mBoundCount, ServiceState.SERVICE_BOUND, mBoundState, mBoundStartTime, now, totalTime, !dumpSummary || dumpAll); @@ -393,11 +432,19 @@ public final class ServiceState { pw.print(" op count "); pw.print(count); pw.println(":"); dumpTime(pw, prefixInner, serviceType, state, startTime, now); } else { - long myTime = dumpTime(null, null, serviceType, state, startTime, now); + long myTime = dumpTimeInternal(null, null, serviceType, state, startTime, now, + true); pw.print(prefix); pw.print(headerPrefix); pw.print(header); pw.print(" count "); pw.print(count); pw.print(" / time "); + boolean isRunning = myTime < 0; + if (isRunning) { + myTime = -myTime; + } DumpUtils.printPercent(pw, (double)myTime/(double)totalTime); + if (isRunning) { + pw.print(" (running)"); + } pw.println(); } } @@ -405,8 +452,14 @@ public final class ServiceState { public long dumpTime(PrintWriter pw, String prefix, int serviceType, int curState, long curStartTime, long now) { + return dumpTimeInternal(pw, prefix, serviceType, curState, curStartTime, now, false); + } + + long dumpTimeInternal(PrintWriter pw, String prefix, + int serviceType, int curState, long curStartTime, long now, boolean negativeIfRunning) { long totalTime = 0; int printedScreen = -1; + boolean isRunning = false; for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) { int printedMem = -1; for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) { @@ -415,6 +468,7 @@ public final class ServiceState { String running = ""; if (curState == state && pw != null) { running = " (running)"; + isRunning = true; } if (time != 0) { if (pw != null) { @@ -438,7 +492,7 @@ public final class ServiceState { TimeUtils.formatDuration(totalTime, pw); pw.println(); } - return totalTime; + return (isRunning && negativeIfRunning) ? -totalTime : totalTime; } public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers, @@ -447,6 +501,9 @@ public final class ServiceState { ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now); dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName, ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now); + dumpTimeCheckin(pw, "pkgsvc-fg", pkgName, uid, vers, serviceName, + ServiceState.SERVICE_FOREGROUND, mForegroundCount, mForegroundState, + mForegroundStartTime, now); dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName, ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now); dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName, @@ -497,6 +554,6 @@ public final class ServiceState { public String toString() { return "ServiceState{" + Integer.toHexString(System.identityHashCode(this)) + " " + mName + " pkg=" + mPackage + " proc=" - + Integer.toHexString(System.identityHashCode(this)) + "}"; + + Integer.toHexString(System.identityHashCode(mProc)) + "}"; } } diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java index 91b205479988..6b8703d37f70 100644 --- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java +++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java @@ -175,7 +175,6 @@ public class SparseMappingTable { * Get the value for the given key and offset from that key. * * @param key A key as obtained from getKey or getOrAddKey. - * @param value The value to set. */ public long getValue(int key) { return getValue(key, 0); @@ -187,7 +186,6 @@ public class SparseMappingTable { * @param key A key as obtained from getKey or getOrAddKey. * @param index The offset from that key. Must be less than the count * provided to getOrAddKey when the space was allocated. - * @param value The value to set. * * @return the value, or 0 in case of an error */ diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index c4d08c7dc5d6..d1c279918bb4 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -194,7 +194,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); + throw protocolExceptionWithCause("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -244,7 +244,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); + throw protocolExceptionWithCause("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -341,7 +341,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing idx " + idx, e); + throw protocolExceptionWithCause("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -378,4 +378,10 @@ public class NetworkStatsFactory { @VisibleForTesting public static native int nativeReadNetworkStatsDev(NetworkStats stats); + + private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) { + ProtocolException pe = new ProtocolException(message); + pe.initCause(cause); + return pe; + } } diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 79d2570256fd..df59f79b0f20 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12709,7 +12709,7 @@ public class BatteryStatsImpl extends BatteryStats { if (mMinLearnedBatteryCapacity == -1) { mMinLearnedBatteryCapacity = chargeFullUAh; } else { - Math.min(mMinLearnedBatteryCapacity, chargeFullUAh); + mMinLearnedBatteryCapacity = Math.min(mMinLearnedBatteryCapacity, chargeFullUAh); } mMaxLearnedBatteryCapacity = Math.max(mMaxLearnedBatteryCapacity, chargeFullUAh); } diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java index fbb99e423cd6..20eab92d018b 100644 --- a/core/java/com/android/internal/os/BinderCallsStats.java +++ b/core/java/com/android/internal/os/BinderCallsStats.java @@ -21,6 +21,8 @@ import android.os.SystemClock; import android.os.UserHandle; import android.text.format.DateFormat; import android.util.ArrayMap; +import android.util.Log; +import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -29,10 +31,12 @@ import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.ToDoubleFunction; @@ -41,25 +45,33 @@ import java.util.function.ToDoubleFunction; * per thread, uid or call description. */ public class BinderCallsStats { + public static final boolean ENABLED_DEFAULT = true; + public static final boolean DETAILED_TRACKING_DEFAULT = true; + public static final int PERIODIC_SAMPLING_INTERVAL_DEFAULT = 10; + + private static final String TAG = "BinderCallsStats"; private static final int CALL_SESSIONS_POOL_SIZE = 100; private static final int PERIODIC_SAMPLING_INTERVAL = 10; + private static final int MAX_EXCEPTION_COUNT_SIZE = 50; + private static final String EXCEPTION_COUNT_OVERFLOW_NAME = "overflow"; + private static final CallSession NOT_ENABLED = new CallSession(); private static final BinderCallsStats sInstance = new BinderCallsStats(); - private volatile boolean mDetailedTracking = false; + private volatile boolean mEnabled = ENABLED_DEFAULT; + private volatile boolean mDetailedTracking = DETAILED_TRACKING_DEFAULT; + private volatile int mPeriodicSamplingInterval = PERIODIC_SAMPLING_INTERVAL_DEFAULT; @GuardedBy("mLock") private final SparseArray<UidEntry> mUidEntries = new SparseArray<>(); + @GuardedBy("mLock") + private final ArrayMap<String, Integer> mExceptionCounts = new ArrayMap<>(); private final Queue<CallSession> mCallSessionsPool = new ConcurrentLinkedQueue<>(); private final Object mLock = new Object(); private long mStartTime = System.currentTimeMillis(); @GuardedBy("mLock") private UidEntry mSampledEntries = new UidEntry(-1); - private BinderCallsStats() { - } - - @VisibleForTesting - public BinderCallsStats(boolean detailedTracking) { - mDetailedTracking = detailedTracking; + @VisibleForTesting // Use getInstance() instead. + public BinderCallsStats() { } public CallSession callStarted(Binder binder, int code) { @@ -67,10 +79,15 @@ public class BinderCallsStats { } private CallSession callStarted(String className, int code) { + if (!mEnabled) { + return NOT_ENABLED; + } + CallSession s = mCallSessionsPool.poll(); if (s == null) { s = new CallSession(); } + s.callStat.className = className; s.callStat.msg = code; s.exceptionThrown = false; @@ -83,7 +100,7 @@ public class BinderCallsStats { s.timeStarted = getElapsedRealtimeMicro(); } else { s.sampledCallStat = mSampledEntries.getOrCreate(s.callStat); - if (s.sampledCallStat.callCount % PERIODIC_SAMPLING_INTERVAL == 0) { + if (s.sampledCallStat.callCount % mPeriodicSamplingInterval == 0) { s.cpuTimeStarted = getThreadTimeMicro(); s.timeStarted = getElapsedRealtimeMicro(); } @@ -94,7 +111,23 @@ public class BinderCallsStats { public void callEnded(CallSession s, int parcelRequestSize, int parcelReplySize) { Preconditions.checkNotNull(s); + if (s == NOT_ENABLED) { + return; + } + + processCallEnded(s, parcelRequestSize, parcelReplySize); + + if (mCallSessionsPool.size() < CALL_SESSIONS_POOL_SIZE) { + mCallSessionsPool.add(s); + } + } + + private void processCallEnded(CallSession s, int parcelRequestSize, int parcelReplySize) { synchronized (mLock) { + if (!mEnabled) { + return; + } + long duration; long latencyDuration; if (mDetailedTracking) { @@ -108,7 +141,7 @@ public class BinderCallsStats { latencyDuration = getElapsedRealtimeMicro() - s.timeStarted; } else { // callCount is always incremented, but time only once per sampling interval - long samplesCount = cs.callCount / PERIODIC_SAMPLING_INTERVAL + 1; + long samplesCount = cs.callCount / mPeriodicSamplingInterval + 1; duration = cs.cpuTimeMicros / samplesCount; latencyDuration = cs.latencyMicros / samplesCount; } @@ -122,33 +155,30 @@ public class BinderCallsStats { mUidEntries.put(callingUid, uidEntry); } + CallStat callStat; if (mDetailedTracking) { // Find CallStat entry and update its total time - CallStat callStat = uidEntry.getOrCreate(s.callStat); - callStat.callCount++; - callStat.cpuTimeMicros += duration; - callStat.latencyMicros += latencyDuration; + callStat = uidEntry.getOrCreate(s.callStat); callStat.exceptionCount += s.exceptionThrown ? 1 : 0; - callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration); callStat.maxRequestSizeBytes = Math.max(callStat.maxRequestSizeBytes, parcelRequestSize); callStat.maxReplySizeBytes = Math.max(callStat.maxReplySizeBytes, parcelReplySize); } else { // update sampled timings in the beginning of each interval - if (s.cpuTimeStarted >= 0) { - s.sampledCallStat.cpuTimeMicros += duration; - s.sampledCallStat.latencyMicros += latencyDuration; - } - s.sampledCallStat.callCount++; + callStat = s.sampledCallStat; + } + callStat.callCount++; + if (s.cpuTimeStarted >= 0) { + callStat.cpuTimeMicros += duration; + callStat.maxCpuTimeMicros = Math.max(callStat.maxCpuTimeMicros, duration); + callStat.latencyMicros += latencyDuration; + callStat.maxLatencyMicros = Math.max(callStat.maxLatencyMicros, latencyDuration); } uidEntry.cpuTimeMicros += duration; uidEntry.callCount++; } - if (mCallSessionsPool.size() < CALL_SESSIONS_POOL_SIZE) { - mCallSessionsPool.add(s); - } } /** @@ -158,9 +188,25 @@ public class BinderCallsStats { * <li>Do not throw an exception in this method, it will swallow the original exception thrown * by the binder transaction. */ - public void callThrewException(CallSession s) { + public void callThrewException(CallSession s, Exception exception) { Preconditions.checkNotNull(s); + if (!mEnabled) { + return; + } s.exceptionThrown = true; + try { + String className = exception.getClass().getName(); + synchronized (mLock) { + if (mExceptionCounts.size() >= MAX_EXCEPTION_COUNT_SIZE) { + className = EXCEPTION_COUNT_OVERFLOW_NAME; + } + Integer count = mExceptionCounts.get(className); + mExceptionCounts.put(className, count == null ? 1 : count + 1); + } + } catch (RuntimeException e) { + // Do not propagate the exception. We do not want to swallow original exception. + Log.wtf(TAG, "Unexpected exception while updating mExceptionCounts", e); + } } public void dump(PrintWriter pw, Map<Integer,String> appIdToPkgNameMap, boolean verbose) { @@ -170,6 +216,11 @@ public class BinderCallsStats { } private void dumpLocked(PrintWriter pw, Map<Integer,String> appIdToPkgNameMap, boolean verbose) { + if (!mEnabled) { + pw.println("Binder calls stats disabled."); + return; + } + long totalCallsCount = 0; long totalCpuTime = 0; pw.print("Start time: "); @@ -189,17 +240,18 @@ public class BinderCallsStats { StringBuilder sb = new StringBuilder(); if (mDetailedTracking) { pw.println("Per-UID raw data " + datasetSizeDesc - + "(uid, call_desc, cpu_time_micros, latency_time_micros, " - + "max_latency_time_micros, exception_count, max_request_size_bytes, " - + "max_reply_size_bytes, call_count):"); + + "(package/uid, call_desc, cpu_time_micros, max_cpu_time_micros, " + + "latency_time_micros, max_latency_time_micros, exception_count, " + + "max_request_size_bytes, max_reply_size_bytes, call_count):"); List<UidEntry> topEntries = verbose ? entries : getHighestValues(entries, value -> value.cpuTimeMicros, 0.9); for (UidEntry uidEntry : topEntries) { for (CallStat e : uidEntry.getCallStatsList()) { sb.setLength(0); sb.append(" ") - .append(uidEntry.uid).append(",").append(e) + .append(uidToString(uidEntry.uid, appIdToPkgNameMap)) .append(',').append(e.cpuTimeMicros) + .append(',').append(e.maxCpuTimeMicros) .append(',').append(e.latencyMicros) .append(',').append(e.maxLatencyMicros) .append(',').append(e.exceptionCount) @@ -222,7 +274,7 @@ public class BinderCallsStats { for (CallStat e : sampledStatsList) { sb.setLength(0); sb.append(" ").append(e) - .append(',').append(e.cpuTimeMicros * PERIODIC_SAMPLING_INTERVAL) + .append(',').append(e.cpuTimeMicros * mPeriodicSamplingInterval) .append(',').append(e.callCount) .append(',').append(e.exceptionCount); pw.println(sb); @@ -243,6 +295,18 @@ public class BinderCallsStats { pw.println(String.format(" Summary: total_cpu_time=%d, " + "calls_count=%d, avg_call_cpu_time=%.0f", totalCpuTime, totalCallsCount, (double)totalCpuTime / totalCallsCount)); + pw.println(); + + pw.println("Exceptions thrown (exception_count, class_name):"); + List<Pair<String, Integer>> exceptionEntries = new ArrayList<>(); + // We cannot use new ArrayList(Collection) constructor because MapCollections does not + // implement toArray method. + mExceptionCounts.entrySet().iterator().forEachRemaining( + (e) -> exceptionEntries.add(Pair.create(e.getKey(), e.getValue()))); + exceptionEntries.sort((e1, e2) -> Integer.compare(e2.second, e1.second)); + for (Pair<String, Integer> entry : exceptionEntries) { + pw.println(String.format(" %6d %s", entry.second, entry.first)); + } } private static String uidToString(int uid, Map<Integer, String> pkgNameMap) { @@ -260,7 +324,7 @@ public class BinderCallsStats { return Binder.getCallingUid(); } - private long getElapsedRealtimeMicro() { + protected long getElapsedRealtimeMicro() { return SystemClock.elapsedRealtimeNanos() / 1000; } @@ -269,15 +333,36 @@ public class BinderCallsStats { } public void setDetailedTracking(boolean enabled) { - if (enabled != mDetailedTracking) { - reset(); - mDetailedTracking = enabled; + synchronized (mLock) { + if (enabled != mDetailedTracking) { + mDetailedTracking = enabled; + reset(); + } + } + } + + public void setEnabled(boolean enabled) { + synchronized (mLock) { + if (enabled != mEnabled) { + mEnabled = enabled; + reset(); + } + } + } + + public void setSamplingInterval(int samplingInterval) { + synchronized (mLock) { + if (samplingInterval != mPeriodicSamplingInterval) { + mPeriodicSamplingInterval = samplingInterval; + reset(); + } } } public void reset() { synchronized (mLock) { mUidEntries.clear(); + mExceptionCounts.clear(); mSampledEntries.mCallStats.clear(); mStartTime = System.currentTimeMillis(); } @@ -288,11 +373,13 @@ public class BinderCallsStats { public String className; public int msg; public long cpuTimeMicros; + public long maxCpuTimeMicros; public long latencyMicros; public long maxLatencyMicros; + public long callCount; + // The following fields are only computed if mDetailedTracking is set. public long maxRequestSizeBytes; public long maxReplySizeBytes; - public long callCount; public long exceptionCount; CallStat() { @@ -411,6 +498,11 @@ public class BinderCallsStats { } @VisibleForTesting + public ArrayMap<String, Integer> getExceptionCounts() { + return mExceptionCounts; + } + + @VisibleForTesting public static <T> List<T> getHighestValues(List<T> list, ToDoubleFunction<T> toDouble, double percentile) { List<T> sortedList = new ArrayList<>(list); diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java index 621619c5134d..be645fe707c6 100644 --- a/core/java/com/android/internal/util/ArrayUtils.java +++ b/core/java/com/android/internal/util/ArrayUtils.java @@ -626,4 +626,17 @@ public class ArrayUtils { public static @NonNull String[] defeatNullable(@Nullable String[] val) { return (val != null) ? val : EmptyArray.STRING; } + + /** + * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds. + * + * @param len length of the array. Must be non-negative + * @param index the index to check + * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array + */ + public static void checkBounds(int len, int index) { + if (index < 0 || len <= index) { + throw new ArrayIndexOutOfBoundsException("length=" + len + "; index=" + index); + } + } } diff --git a/core/java/com/android/internal/util/DumpUtils.java b/core/java/com/android/internal/util/DumpUtils.java index 7fd83bc6c8b9..f6d80a572c75 100644 --- a/core/java/com/android/internal/util/DumpUtils.java +++ b/core/java/com/android/internal/util/DumpUtils.java @@ -34,9 +34,18 @@ import java.util.function.Predicate; /** * Helper functions for dumping the state of system services. * Test: - atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java + atest FrameworksCoreTests:DumpUtilsTest */ public final class DumpUtils { + + /** + * List of component names that should be dumped in the bug report critical section. + * + * @hide + */ + public static final ComponentName[] CRITICAL_SECTION_COMPONENTS = { + new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService") + }; private static final String TAG = "DumpUtils"; private static final boolean DEBUG = false; @@ -213,6 +222,45 @@ public final class DumpUtils { } /** + * Return whether a package should be dumped in the critical section. + */ + private static boolean isCriticalPackage(@Nullable ComponentName cname) { + if (cname == null) { + return false; + } + + for (int i = 0; i < CRITICAL_SECTION_COMPONENTS.length; i++) { + if (cname.equals(CRITICAL_SECTION_COMPONENTS[i])) { + return true; + } + } + return false; + } + + /** + * Return whether a package name is considered to be part of the platform and in the critical + * section. + * + * @hide + */ + public static boolean isPlatformCriticalPackage(@Nullable ComponentName.WithComponentName wcn) { + return (wcn != null) && isPlatformPackage(wcn.getComponentName()) && + isCriticalPackage(wcn.getComponentName()); + } + + /** + * Return whether a package name is considered to be part of the platform but not in the the + * critical section. + * + * @hide + */ + public static boolean isPlatformNonCriticalPackage( + @Nullable ComponentName.WithComponentName wcn) { + return (wcn != null) && isPlatformPackage(wcn.getComponentName()) && + !isCriticalPackage(wcn.getComponentName()); + } + + /** * Used for dumping providers and services. Return a predicate for a given filter string. * @hide */ @@ -238,6 +286,16 @@ public final class DumpUtils { return DumpUtils::isNonPlatformPackage; } + // Dump all platform-critical? + if ("all-platform-critical".equals(filterString)) { + return DumpUtils::isPlatformCriticalPackage; + } + + // Dump all platform-non-critical? + if ("all-platform-non-critical".equals(filterString)) { + return DumpUtils::isPlatformNonCriticalPackage; + } + // Is the filter a component name? If so, do an exact match. final ComponentName filterCname = ComponentName.unflattenFromString(filterString); if (filterCname != null) { diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index c3ba9ba82826..7e2bad2f7946 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -155,9 +155,8 @@ static struct thread_dispatch_offsets_t static constexpr int32_t PROXY_WARN_INTERVAL = 5000; static constexpr uint32_t GC_INTERVAL = 1000; -// Protected by gProxyLock. We warn if this gets too large. -static int32_t gNumProxies = 0; -static int32_t gProxiesWarned = 0; +static std::atomic<uint32_t> gNumProxies(0); +static std::atomic<uint32_t> gProxiesWarned(0); // Number of GlobalRefs held by JavaBBinders. static std::atomic<uint32_t> gNumLocalRefsCreated(0); @@ -632,12 +631,6 @@ BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) { return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData); } -static Mutex gProxyLock; - -// We may cache a single BinderProxyNativeData node to avoid repeat allocation. -// All fields are null. Protected by gProxyLock. -static BinderProxyNativeData *gNativeDataCache; - // If the argument is a JavaBBinder, return the Java object that was used to create it. // Otherwise return a BinderProxy for the IBinder. If a previous call was passed the // same IBinder, and the original BinderProxy is still alive, return the same BinderProxy. @@ -652,36 +645,31 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) return object; } - // For the rest of the function we will hold this lock, to serialize - // looking/creation/destruction of Java proxies for native Binder proxies. - AutoMutex _l(gProxyLock); + BinderProxyNativeData* nativeData = new BinderProxyNativeData(); + nativeData->mOrgue = new DeathRecipientList; + nativeData->mObject = val; - BinderProxyNativeData* nativeData = gNativeDataCache; - if (nativeData == nullptr) { - nativeData = new BinderProxyNativeData(); - } - // gNativeDataCache is now logically empty. jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get()); if (env->ExceptionCheck()) { // In the exception case, getInstance still took ownership of nativeData. - gNativeDataCache = nullptr; return NULL; } BinderProxyNativeData* actualNativeData = getBPNativeData(env, object); if (actualNativeData == nativeData) { - // New BinderProxy; we still have exclusive access. - nativeData->mOrgue = new DeathRecipientList; - nativeData->mObject = val; - gNativeDataCache = nullptr; - ++gNumProxies; - if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) { - ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies); - gProxiesWarned = gNumProxies; + // Created a new Proxy + uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed); + uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed); + if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) { + // Multiple threads can get here, make sure only one of them gets to + // update the warn counter. + if (gProxiesWarned.compare_exchange_strong(numLastWarned, + numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) { + ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies); + } } } else { - // nativeData wasn't used. Reuse it the next time. - gNativeDataCache = nativeData; + delete nativeData; } return object; @@ -959,8 +947,7 @@ jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz) jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz) { - AutoMutex _l(gProxyLock); - return gNumProxies; + return gNumProxies.load(); } jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz) @@ -1008,8 +995,6 @@ static void android_os_BinderInternal_proxyLimitcallback(int uid) { JNIEnv *env = AndroidRuntime::getJNIEnv(); { - // Calls into BinderProxy must be serialized - AutoMutex _l(gProxyLock); env->CallStaticObjectMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mDumpProxyDebugInfo); } @@ -1367,9 +1352,6 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, static void BinderProxy_destroy(void* rawNativeData) { - // Don't race with construction/initialization - AutoMutex _l(gProxyLock); - BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData; LOGDEATH("Destroying BinderProxy: binder=%p drl=%p\n", nativeData->mObject.get(), nativeData->mOrgue.get()); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 095252c28332..10da89227f51 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -114,8 +114,8 @@ status_t NativeInputEventSender::sendKeyEvent(uint32_t seq, const KeyEvent* even uint32_t publishedSeq = mNextPublishedSeq++; status_t status = mInputPublisher.publishKeyEvent(publishedSeq, - event->getDeviceId(), event->getSource(), event->getAction(), event->getFlags(), - event->getKeyCode(), event->getScanCode(), event->getMetaState(), + event->getDeviceId(), event->getSource(), event->getDisplayId(), event->getAction(), + event->getFlags(), event->getKeyCode(), event->getScanCode(), event->getMetaState(), event->getRepeatCount(), event->getDownTime(), event->getEventTime()); if (status) { ALOGW("Failed to send key event on channel '%s'. status=%d", @@ -135,8 +135,7 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent for (size_t i = 0; i <= event->getHistorySize(); i++) { publishedSeq = mNextPublishedSeq++; status_t status = mInputPublisher.publishMotionEvent(publishedSeq, - event->getDeviceId(), event->getSource(), - event->getDisplayId(), + event->getDeviceId(), event->getSource(), event->getDisplayId(), event->getAction(), event->getActionButton(), event->getFlags(), event->getEdgeFlags(), event->getMetaState(), event->getButtonState(), event->getXOffset(), event->getYOffset(), diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index 8a6e745b60a8..f0107723a43e 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -39,6 +39,7 @@ static struct { jfieldID mDeviceId; jfieldID mSource; + jfieldID mDisplayId; jfieldID mMetaState; jfieldID mAction; jfieldID mKeyCode; @@ -65,6 +66,7 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) { event->getScanCode(), event->getFlags(), event->getSource(), + event->getDisplayId(), NULL); if (env->ExceptionCheck()) { ALOGE("An exception occurred while obtaining a key event."); @@ -79,6 +81,7 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, KeyEvent* event) { jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId); jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource); + jint displayId = env->GetIntField(eventObj, gKeyEventClassInfo.mDisplayId); jint metaState = env->GetIntField(eventObj, gKeyEventClassInfo.mMetaState); jint action = env->GetIntField(eventObj, gKeyEventClassInfo.mAction); jint keyCode = env->GetIntField(eventObj, gKeyEventClassInfo.mKeyCode); @@ -88,7 +91,8 @@ status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj, jlong downTime = env->GetLongField(eventObj, gKeyEventClassInfo.mDownTime); jlong eventTime = env->GetLongField(eventObj, gKeyEventClassInfo.mEventTime); - event->initialize(deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, + event->initialize(deviceId, source, displayId, action, flags, keyCode, scanCode, metaState, + repeatCount, milliseconds_to_nanoseconds(downTime), milliseconds_to_nanoseconds(eventTime)); return OK; @@ -131,12 +135,14 @@ int register_android_view_KeyEvent(JNIEnv* env) { gKeyEventClassInfo.clazz = MakeGlobalRefOrDie(env, clazz); gKeyEventClassInfo.obtain = GetStaticMethodIDOrDie(env, gKeyEventClassInfo.clazz, - "obtain", "(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;"); + "obtain", "(JJIIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;"); gKeyEventClassInfo.recycle = GetMethodIDOrDie(env, gKeyEventClassInfo.clazz, "recycle", "()V"); gKeyEventClassInfo.mDeviceId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDeviceId", "I"); gKeyEventClassInfo.mSource = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mSource", "I"); + gKeyEventClassInfo.mDisplayId = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mDisplayId", + "I"); gKeyEventClassInfo.mMetaState = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mMetaState", "I"); gKeyEventClassInfo.mAction = GetFieldIDOrDie(env, gKeyEventClassInfo.clazz, "mAction", "I"); diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 22bbc3c48119..46b19bdf660f 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -222,6 +222,11 @@ static jboolean android_view_RenderNode_setHasOverlappingRendering(jlong renderN RenderNode::GENERIC); } +static void android_view_RenderNode_setUsageHint(jlong renderNodePtr, jint usageHint) { + RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); + renderNode->setUsageHint(static_cast<UsageHint>(usageHint)); +} + static jboolean android_view_RenderNode_setElevation(jlong renderNodePtr, float elevation) { return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z); } @@ -614,6 +619,7 @@ static const JNINativeMethod gMethods[] = { { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha }, { "nSetHasOverlappingRendering", "(JZ)Z", (void*) android_view_RenderNode_setHasOverlappingRendering }, + { "nSetUsageHint", "(JI)V", (void*) android_view_RenderNode_setUsageHint }, { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation }, { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX }, { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index caf4e4b48e61..e30a3e7adc0c 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -45,6 +45,7 @@ #include <unistd.h> #include "android-base/logging.h" +#include <android-base/properties.h> #include <android-base/file.h> #include <android-base/stringprintf.h> #include <cutils/fs.h> @@ -70,6 +71,7 @@ namespace { using android::String8; using android::base::StringPrintf; using android::base::WriteStringToFile; +using android::base::GetBoolProperty; #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ append(StringPrintf(__VA_ARGS__)) @@ -931,12 +933,16 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!"); } - // Assign system_server to the correct memory cgroup. - // Not all devices mount /dev/memcg so check for the file first - // to avoid unnecessarily printing errors and denials in the logs. - if (!access("/dev/memcg/system/tasks", F_OK) && + bool low_ram_device = GetBoolProperty("ro.config.low_ram", false); + bool per_app_memcg = GetBoolProperty("ro.config.per_app_memcg", low_ram_device); + if (per_app_memcg) { + // Assign system_server to the correct memory cgroup. + // Not all devices mount /dev/memcg so check for the file first + // to avoid unnecessarily printing errors and denials in the logs. + if (!access("/dev/memcg/system/tasks", F_OK) && !WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) { - ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid); + ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid); + } } } return pid; diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 7467d8f2e961..2de53b97312a 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -319,6 +319,8 @@ message WindowStateProto { optional bool removed = 36; optional bool is_on_screen = 37; optional bool is_visible = 38; + optional bool pending_forced_seamless_rotation = 39; + optional int64 finished_forced_seamless_rotation_frame = 40; } message IdentifierProto { diff --git a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml index e9475f52d22a..ff95aeae1683 100644 --- a/core/res/res/anim/lock_screen_behind_enter_fade_in.xml +++ b/core/res/res/anim/lock_screen_behind_enter_fade_in.xml @@ -16,7 +16,6 @@ --> <alpha xmlns:android="http://schemas.android.com/apk/res/android" - android:background="#ff000000" android:detachWallpaper="true" android:shareInterpolator="false" android:interpolator="@interpolator/linear" diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml new file mode 100644 index 000000000000..23b0a24fff98 --- /dev/null +++ b/core/res/res/values-night/values.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<resources> + <style name="Theme.DeviceDefault.QuickSettings" parent="android:Theme.DeviceDefault"> + <!-- Color palette --> + <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item> + <item name="colorSecondary">@color/secondary_device_default_settings</item> + <item name="colorAccent">@color/accent_device_default_dark</item> + <item name="colorError">@color/error_color_device_default_dark</item> + <item name="colorControlNormal">?attr/textColorPrimary</item> + <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item> + + <!-- QS panel background --> + <item name="colorBackgroundFloating">@color/material_grey_900</item> + + <!-- volume background --> + <item name="panelColorBackground">@color/material_grey_800</item> + </style> +</resources>
\ No newline at end of file diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d2684ce28ff2..44eea30cf09f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1477,7 +1477,7 @@ used for, typically, account ID or password input. It is expected that IMEs normally are able to input ASCII even without being told so (such IMEs already respect this flag in a sense), but there could be some cases they - aren't when, for instance, only non-ASCII input languagaes like Arabic, + aren't when, for instance, only non-ASCII input languages like Arabic, Greek, Hebrew, Russian are enabled in the IME. Applications need to be aware that the flag is not a guarantee, and not all IMEs will respect it. However, it is strongly recommended for IME authors to respect this flag @@ -3161,7 +3161,7 @@ enabled by a ViewGroup for all its children in specific situations (for instance during a scrolling.) This property lets you persist the cache in memory after its initial usage. Persisting the cache consumes more - memory but may prevent frequent garbage collection is the cache is created + memory but may prevent frequent garbage collection if the cache is created over and over again. By default the persistence is set to scrolling. Deprecated: The view drawing cache was largely made obsolete with the introduction of hardware-accelerated rendering in API 11. --> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index aef48fa9a885..18624370ccfa 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -583,12 +583,14 @@ <integer translatable="false" name="config_wifi_framework_min_rx_rate_for_staying_on_network">16</integer> <!-- Integer parameters of the wifi to cellular handover feature wifi should not stick to bad networks --> - <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer> - <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-82</integer> + <!-- Integer threshold for low network score, should be somewhat less than the entry threshhold --> + <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-80</integer> + <!-- Integer threshold, do not connect to APs with RSSI lower than the entry threshold --> + <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-77</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer> - <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer> - <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-85</integer> + <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-83</integer> + <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-80</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer> @@ -2966,6 +2968,14 @@ --> <string translatable="false" name="config_mainBuiltInDisplayCutout"></string> + <!-- Like config_mainBuiltInDisplayCutout, but this path is used to report the + one single bounding rect per device edge to the app via + {@link DisplayCutout#getBoundingRect}. Note that this path should try to match the visual + appearance of the cutout as much as possible, and may be smaller than + config_mainBuiltInDisplayCutout + --> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> @@ -3487,4 +3497,7 @@ <!-- Whether or not we should show the option to show battery percentage --> <bool name="config_battery_percentage_setting_available">true</bool> + + <!-- Whether or not battery saver should be "sticky" when manually enabled. --> + <bool name="config_batterySaverStickyBehaviourDisabled">false</bool> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6054180d9193..99001e3a9209 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3364,6 +3364,7 @@ <java-symbol type="string" name="global_action_logout" /> <java-symbol type="string" name="config_mainBuiltInDisplayCutout" /> + <java-symbol type="string" name="config_mainBuiltInDisplayCutoutRectApproximation" /> <java-symbol type="drawable" name="messaging_user" /> <java-symbol type="bool" name="config_fillMainBuiltInDisplayCutout" /> <java-symbol type="drawable" name="ic_logout" /> @@ -3405,6 +3406,7 @@ <java-symbol type="string" name="notification_app_name_settings" /> <java-symbol type="integer" name="config_lowBatteryAutoTriggerDefaultLevel" /> + <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" /> <!-- For car devices --> <java-symbol type="string" name="car_loading_profile" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 7d489874f742..f91d14988d29 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -124,6 +124,7 @@ public class SettingsBackupTest { Settings.Global.BATTERY_DISCHARGE_THRESHOLD, Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS, Settings.Global.BATTERY_STATS_CONSTANTS, + Settings.Global.BINDER_CALLS_STATS, Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, Settings.Global.BLE_SCAN_LOW_POWER_WINDOW_MS, Settings.Global.BLE_SCAN_LOW_POWER_INTERVAL_MS, @@ -596,13 +597,15 @@ public class SettingsBackupTest { Settings.Secure.SEARCH_THREAD_KEEPALIVE_SECONDS, Settings.Secure.SEARCH_WEB_RESULTS_OVERRIDE_LIMIT, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, + Settings.Secure.SELECTED_SPELL_CHECKER, // Intentionally removed in Q + Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, // Intentionally removed in Q Settings.Secure.SETTINGS_CLASSNAME, Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, // candidate? Settings.Secure.SHOW_ROTATION_SUGGESTIONS, Settings.Secure.SKIP_FIRST_USE_HINTS, // candidate? Settings.Secure.SLEEP_TIMEOUT, Settings.Secure.SMS_DEFAULT_APPLICATION, - Settings.Secure.THEME_MODE, + Settings.Secure.SPELL_CHECKER_ENABLED, // Intentionally removed in Q Settings.Secure.TRUST_AGENTS_INITIALIZED, Settings.Secure.TV_INPUT_CUSTOM_LABELS, Settings.Secure.TV_INPUT_HIDDEN_INPUTS, diff --git a/core/tests/coretests/src/android/view/KeyEventTest.java b/core/tests/coretests/src/android/view/KeyEventTest.java index aabf81606864..b9d95e542f11 100644 --- a/core/tests/coretests/src/android/view/KeyEventTest.java +++ b/core/tests/coretests/src/android/view/KeyEventTest.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.Display.INVALID_DISPLAY; + import static org.junit.Assert.assertEquals; import android.support.test.filters.SmallTest; @@ -28,12 +30,71 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class KeyEventTest { + private static final int DOWN_TIME = 50; + private static final long EVENT_TIME = 100; + private static final int ACTION = KeyEvent.ACTION_DOWN; + private static final int KEYCODE = KeyEvent.KEYCODE_0; + private static final int REPEAT = 0; + private static final int METASTATE = 0; + private static final int DEVICE_ID = 0; + private static final int SCAN_CODE = 0; + private static final int FLAGS = 0; + private static final int SOURCE = InputDevice.SOURCE_KEYBOARD; + private static final String CHARACTERS = null; + @Test public void testObtain() { - KeyEvent keyEvent = KeyEvent.obtain(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0, - 0, 0, 0, 0, 0, InputDevice.SOURCE_KEYBOARD, null); - assertEquals(KeyEvent.ACTION_DOWN, keyEvent.getAction()); - assertEquals(KeyEvent.KEYCODE_0, keyEvent.getKeyCode()); - assertEquals(InputDevice.SOURCE_KEYBOARD, keyEvent.getSource()); + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + assertEquals(DOWN_TIME, keyEvent.getDownTime()); + assertEquals(EVENT_TIME, keyEvent.getEventTime()); + assertEquals(ACTION, keyEvent.getAction()); + assertEquals(KEYCODE, keyEvent.getKeyCode()); + assertEquals(REPEAT, keyEvent.getRepeatCount()); + assertEquals(METASTATE, keyEvent.getMetaState()); + assertEquals(DEVICE_ID, keyEvent.getDeviceId()); + assertEquals(SCAN_CODE, keyEvent.getScanCode()); + assertEquals(FLAGS, keyEvent.getFlags()); + assertEquals(SOURCE, keyEvent.getSource()); + assertEquals(INVALID_DISPLAY, keyEvent.getDisplayId()); + assertEquals(CHARACTERS, keyEvent.getCharacters()); + } + + @Test + public void testObtainFromKeyEvent() { + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, CHARACTERS); + KeyEvent keyEvent2 = KeyEvent.obtain(keyEvent); + assertEquals(keyEvent.getDownTime(), keyEvent2.getDownTime()); + assertEquals(keyEvent.getEventTime(), keyEvent2.getEventTime()); + assertEquals(keyEvent.getAction(), keyEvent2.getAction()); + assertEquals(keyEvent.getKeyCode(), keyEvent2.getKeyCode()); + assertEquals(keyEvent.getRepeatCount(), keyEvent2.getRepeatCount()); + assertEquals(keyEvent.getMetaState(), keyEvent2.getMetaState()); + assertEquals(keyEvent.getDeviceId(), keyEvent2.getDeviceId()); + assertEquals(keyEvent.getScanCode(), keyEvent2.getScanCode()); + assertEquals(keyEvent.getFlags(), keyEvent2.getFlags()); + assertEquals(keyEvent.getSource(), keyEvent2.getSource()); + assertEquals(keyEvent.getDisplayId(), keyEvent2.getDisplayId()); + assertEquals(keyEvent.getCharacters(), keyEvent2.getCharacters()); + } + + @Test + public void testObtainWithDisplayId() { + final int displayId = 5; + KeyEvent keyEvent = KeyEvent.obtain(DOWN_TIME, EVENT_TIME, ACTION, KEYCODE, REPEAT, + METASTATE, DEVICE_ID, SCAN_CODE, FLAGS, SOURCE, displayId, CHARACTERS); + assertEquals(DOWN_TIME, keyEvent.getDownTime()); + assertEquals(EVENT_TIME, keyEvent.getEventTime()); + assertEquals(ACTION, keyEvent.getAction()); + assertEquals(KEYCODE, keyEvent.getKeyCode()); + assertEquals(REPEAT, keyEvent.getRepeatCount()); + assertEquals(METASTATE, keyEvent.getMetaState()); + assertEquals(DEVICE_ID, keyEvent.getDeviceId()); + assertEquals(SCAN_CODE, keyEvent.getScanCode()); + assertEquals(FLAGS, keyEvent.getFlags()); + assertEquals(SOURCE, keyEvent.getSource()); + assertEquals(displayId, keyEvent.getDisplayId()); + assertEquals(CHARACTERS, keyEvent.getCharacters()); } } diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java index b7fef13d5e9d..914fb7409c74 100644 --- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java +++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java @@ -20,14 +20,19 @@ import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.ArrayMap; import android.util.SparseArray; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.junit.Assert.assertEquals; @@ -41,7 +46,9 @@ public class BinderCallsStatsTest { @Test public void testDetailedOff() { - TestBinderCallsStats bcs = new TestBinderCallsStats(false); + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(false); + Binder binder = new Binder(); BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); bcs.time += 10; @@ -93,7 +100,9 @@ public class BinderCallsStatsTest { @Test public void testDetailedOn() { - TestBinderCallsStats bcs = new TestBinderCallsStats(true); + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); + Binder binder = new Binder(); BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); bcs.time += 10; @@ -140,8 +149,86 @@ public class BinderCallsStatsTest { } @Test + public void testDisabled() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setEnabled(false); + + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.time += 10; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(0, uidEntries.size()); + } + + @Test + public void testDisableInBetweenCall() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setEnabled(true); + + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.time += 10; + bcs.setEnabled(false); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(0, uidEntries.size()); + } + + @Test + public void testEnableInBetweenCall() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setEnabled(false); + + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.time += 10; + bcs.setEnabled(true); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(0, uidEntries.size()); + } + + @Test + public void testSampling() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(false); + bcs.setSamplingInterval(2); + + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.time += 10; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.time += 1000; // shoud be ignored. + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.time += 50; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + SparseArray<BinderCallsStats.UidEntry> uidEntries = bcs.getUidEntries(); + assertEquals(1, uidEntries.size()); + BinderCallsStats.UidEntry uidEntry = uidEntries.get(TEST_UID); + Assert.assertNotNull(uidEntry); + assertEquals(3, uidEntry.callCount); + assertEquals(70, uidEntry.cpuTimeMicros); + assertEquals("Detailed tracking off - no entries should be returned", + 0, uidEntry.getCallStatsList().size()); + + BinderCallsStats.UidEntry sampledEntries = bcs.getSampledEntries(); + List<BinderCallsStats.CallStat> sampledCallStatsList = sampledEntries.getCallStatsList(); + assertEquals(1, sampledCallStatsList.size()); + } + + @Test public void testParcelSize() { - TestBinderCallsStats bcs = new TestBinderCallsStats(true); + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); Binder binder = new Binder(); BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); bcs.time += 10; @@ -155,6 +242,44 @@ public class BinderCallsStatsTest { } @Test + public void testMaxCpu() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.time += 50; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.time += 10; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + List<BinderCallsStats.CallStat> callStatsList = + bcs.getUidEntries().get(TEST_UID).getCallStatsList(); + + assertEquals(50, callStatsList.get(0).maxCpuTimeMicros); + } + + @Test + public void testMaxLatency() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.elapsedTime += 5; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.elapsedTime += 1; + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + List<BinderCallsStats.CallStat> callStatsList = + bcs.getUidEntries().get(TEST_UID).getCallStatsList(); + + assertEquals(5, callStatsList.get(0).maxLatencyMicros); + } + + @Test public void testGetHighestValues() { List<Integer> list = Arrays.asList(1, 2, 3, 4); List<Integer> highestValues = BinderCallsStats @@ -162,12 +287,48 @@ public class BinderCallsStatsTest { assertEquals(Arrays.asList(4, 3, 2), highestValues); } + @Test + public void testExceptionCount() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.callThrewException(callSession, new IllegalStateException()); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.callThrewException(callSession, new IllegalStateException()); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + callSession = bcs.callStarted(binder, 1); + bcs.callThrewException(callSession, new RuntimeException()); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + ArrayMap<String, Integer> expected = new ArrayMap<>(); + expected.put("java.lang.IllegalStateException", 2); + expected.put("java.lang.RuntimeException", 1); + assertEquals(expected, bcs.getExceptionCounts()); + } + + @Test + public void testDumpDoesNotThrowException() { + TestBinderCallsStats bcs = new TestBinderCallsStats(); + bcs.setDetailedTracking(true); + Binder binder = new Binder(); + BinderCallsStats.CallSession callSession = bcs.callStarted(binder, 1); + bcs.callThrewException(callSession, new IllegalStateException()); + bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE); + + PrintWriter pw = new PrintWriter(new StringWriter()); + bcs.dump(pw, new HashMap<>(), true); + } + static class TestBinderCallsStats extends BinderCallsStats { int callingUid = TEST_UID; long time = 1234; + long elapsedTime = 0; - TestBinderCallsStats(boolean detailedTracking) { - super(detailedTracking); + TestBinderCallsStats() { } @Override @@ -176,6 +337,11 @@ public class BinderCallsStatsTest { } @Override + protected long getElapsedRealtimeMicro() { + return elapsedTime; + } + + @Override protected int getCallingUid() { return callingUid; } diff --git a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java index 45b19bccff88..a44b86074ee2 100644 --- a/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/util/DumpUtilsTest.java @@ -15,8 +15,11 @@ */ package com.android.internal.util; +import static com.android.internal.util.DumpUtils.CRITICAL_SECTION_COMPONENTS; import static com.android.internal.util.DumpUtils.filterRecord; import static com.android.internal.util.DumpUtils.isNonPlatformPackage; +import static com.android.internal.util.DumpUtils.isPlatformCriticalPackage; +import static com.android.internal.util.DumpUtils.isPlatformNonCriticalPackage; import static com.android.internal.util.DumpUtils.isPlatformPackage; import android.content.ComponentName; @@ -25,7 +28,7 @@ import junit.framework.TestCase; /** * Run with: - atest /android/pi-dev/frameworks/base/core/tests/coretests/src/com/android/internal/util/DumpTest.java + atest FrameworksCoreTests:DumpUtilsTest */ public class DumpUtilsTest extends TestCase { @@ -89,6 +92,32 @@ public class DumpUtilsTest extends TestCase { assertTrue(isNonPlatformPackage(wcn("com.google.def/abc"))); } + public void testIsPlatformCriticalPackage() { + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertTrue(isPlatformCriticalPackage(() -> componentName)); + assertTrue(isPlatformPackage(componentName)); + } + assertFalse(isPlatformCriticalPackage(wcn("com.google.p/abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android.def/abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android.abc"))); + assertFalse(isPlatformCriticalPackage(wcn("com.android"))); + assertFalse(isPlatformCriticalPackage(wcn(null))); + assertFalse(isPlatformCriticalPackage(null)); + } + + public void testIsPlatformNonCriticalPackage() { + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertFalse(isPlatformNonCriticalPackage(() -> componentName)); + } + assertTrue(isPlatformNonCriticalPackage(wcn("android/abc"))); + assertTrue(isPlatformNonCriticalPackage(wcn("android.abc/abc"))); + assertTrue(isPlatformNonCriticalPackage(wcn("com.android.def/abc"))); + + assertFalse(isPlatformNonCriticalPackage(wcn("com.google.def/abc"))); + assertFalse(isPlatformNonCriticalPackage(wcn(null))); + assertFalse(isPlatformNonCriticalPackage(null)); + } + public void testFilterRecord() { assertFalse(filterRecord(null).test(wcn("com.google.p/abc"))); assertFalse(filterRecord(null).test(wcn("com.android.p/abc"))); @@ -105,6 +134,19 @@ public class DumpUtilsTest extends TestCase { assertFalse(filterRecord("all-non-platform").test(wcn("com.android.p/abc"))); assertFalse(filterRecord("all-non-platform").test(wcn(null))); + for (final ComponentName componentName : CRITICAL_SECTION_COMPONENTS) { + assertTrue(filterRecord("all-platform-critical").test((() -> componentName))); + assertFalse(filterRecord("all-platform-non-critical").test((() -> componentName))); + assertTrue(filterRecord("all-platform").test((() -> componentName))); + } + assertFalse(filterRecord("all-platform-critical").test(wcn("com.google.p/abc"))); + assertFalse(filterRecord("all-platform-critical").test(wcn("com.android.p/abc"))); + assertFalse(filterRecord("all-platform-critical").test(wcn(null))); + + assertTrue(filterRecord("all-platform-non-critical").test(wcn("com.android.p/abc"))); + assertFalse(filterRecord("all-platform-non-critical").test(wcn("com.google.p/abc"))); + assertFalse(filterRecord("all-platform-non-critical").test(wcn(null))); + // Partial string match. assertTrue(filterRecord("abc").test(wcn("com.google.p/.abc"))); assertFalse(filterRecord("abc").test(wcn("com.google.p/.def"))); diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 452024ca063c..89d370f830fa 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -268,6 +268,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private final boolean mIsStrongBoxBacked; private final boolean mUserConfirmationRequired; private final boolean mUnlockedDeviceRequired; + /* + * ***NOTE***: All new fields MUST also be added to the following: + * ParcelableKeyGenParameterSpec class. + * The KeyGenParameterSpec.Builder constructor that takes a KeyGenParameterSpec + */ /** * @hide should be built with Builder @@ -791,6 +796,9 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded(); mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody(); mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment(); + mIsStrongBoxBacked = sourceSpec.isStrongBoxBacked(); + mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired(); + mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired(); } /** diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java index 911bbf8c4eb5..8231dc984579 100644 --- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java @@ -97,11 +97,14 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { out.writeBoolean(mSpec.isRandomizedEncryptionRequired()); out.writeBoolean(mSpec.isUserAuthenticationRequired()); out.writeInt(mSpec.getUserAuthenticationValidityDurationSeconds()); + out.writeBoolean(mSpec.isUserPresenceRequired()); out.writeByteArray(mSpec.getAttestationChallenge()); out.writeBoolean(mSpec.isUniqueIdIncluded()); out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody()); out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment()); - out.writeBoolean(mSpec.isUserPresenceRequired()); + out.writeBoolean(mSpec.isStrongBoxBacked()); + out.writeBoolean(mSpec.isUserConfirmationRequired()); + out.writeBoolean(mSpec.isUnlockedDeviceRequired()); } private static Date readDateOrNull(Parcel in) { @@ -114,19 +117,12 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { } private ParcelableKeyGenParameterSpec(Parcel in) { - String keystoreAlias = in.readString(); - int purposes = in.readInt(); - KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder( - keystoreAlias, purposes); - builder.setUid(in.readInt()); - // KeySize is -1 by default, if the KeyGenParameterSpec previously parcelled had the default - // value, do not set it as this will cause setKeySize to throw. - int keySize = in.readInt(); - if (keySize >= 0) { - builder.setKeySize(keySize); - } + final String keystoreAlias = in.readString(); + final int purposes = in.readInt(); + final int uid = in.readInt(); + final int keySize = in.readInt(); - int keySpecType = in.readInt(); + final int keySpecType = in.readInt(); AlgorithmParameterSpec algorithmSpec = null; if (keySpecType == ALGORITHM_PARAMETER_SPEC_NONE) { algorithmSpec = null; @@ -141,32 +137,60 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable { throw new IllegalArgumentException( String.format("Unknown algorithm parameter spec: %d", keySpecType)); } - if (algorithmSpec != null) { - builder.setAlgorithmParameterSpec(algorithmSpec); - } - builder.setCertificateSubject(new X500Principal(in.createByteArray())); - builder.setCertificateSerialNumber(new BigInteger(in.createByteArray())); - builder.setCertificateNotBefore(new Date(in.readLong())); - builder.setCertificateNotAfter(new Date(in.readLong())); - builder.setKeyValidityStart(readDateOrNull(in)); - builder.setKeyValidityForOriginationEnd(readDateOrNull(in)); - builder.setKeyValidityForConsumptionEnd(readDateOrNull(in)); - String[] digests = in.createStringArray(); - if (digests != null) { - builder.setDigests(digests); - } - builder.setEncryptionPaddings(in.createStringArray()); - builder.setSignaturePaddings(in.createStringArray()); - builder.setBlockModes(in.createStringArray()); - builder.setRandomizedEncryptionRequired(in.readBoolean()); - builder.setUserAuthenticationRequired(in.readBoolean()); - builder.setUserAuthenticationValidityDurationSeconds(in.readInt()); - builder.setAttestationChallenge(in.createByteArray()); - builder.setUniqueIdIncluded(in.readBoolean()); - builder.setUserAuthenticationValidWhileOnBody(in.readBoolean()); - builder.setInvalidatedByBiometricEnrollment(in.readBoolean()); - builder.setUserPresenceRequired(in.readBoolean()); - mSpec = builder.build(); + + final X500Principal certificateSubject = new X500Principal(in.createByteArray()); + final BigInteger certificateSerialNumber = new BigInteger(in.createByteArray()); + final Date certificateNotBefore = new Date(in.readLong()); + final Date certificateNotAfter = new Date(in.readLong()); + final Date keyValidityStartDate = readDateOrNull(in); + final Date keyValidityForOriginationEnd = readDateOrNull(in); + final Date keyValidityForConsumptionEnd = readDateOrNull(in); + final String[] digests = in.createStringArray(); + final String[] encryptionPaddings = in.createStringArray(); + final String[] signaturePaddings = in.createStringArray(); + final String[] blockModes = in.createStringArray(); + final boolean randomizedEncryptionRequired = in.readBoolean(); + final boolean userAuthenticationRequired = in.readBoolean(); + final int userAuthenticationValidityDurationSeconds = in.readInt(); + final boolean userPresenceRequired = in.readBoolean(); + final byte[] attestationChallenge = in.createByteArray(); + final boolean uniqueIdIncluded = in.readBoolean(); + final boolean userAuthenticationValidWhileOnBody = in.readBoolean(); + final boolean invalidatedByBiometricEnrollment = in.readBoolean(); + final boolean isStrongBoxBacked = in.readBoolean(); + final boolean userConfirmationRequired = in.readBoolean(); + final boolean unlockedDeviceRequired = in.readBoolean(); + // The KeyGenParameterSpec is intentionally not constructed using a Builder here: + // The intention is for this class to break if new parameters are added to the + // KeyGenParameterSpec constructor (whereas using a builder would silently drop them). + mSpec = new KeyGenParameterSpec( + keystoreAlias, + uid, + keySize, + algorithmSpec, + certificateSubject, + certificateSerialNumber, + certificateNotBefore, + certificateNotAfter, + keyValidityStartDate, + keyValidityForOriginationEnd, + keyValidityForConsumptionEnd, + purposes, + digests, + encryptionPaddings, + signaturePaddings, + blockModes, + randomizedEncryptionRequired, + userAuthenticationRequired, + userAuthenticationValidityDurationSeconds, + userPresenceRequired, + attestationChallenge, + uniqueIdIncluded, + userAuthenticationValidWhileOnBody, + invalidatedByBiometricEnrollment, + isStrongBoxBacked, + userConfirmationRequired, + unlockedDeviceRequired); } public static final Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() { diff --git a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java index 254b6be77ea8..32f8ec44d11f 100644 --- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java +++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java @@ -77,6 +77,9 @@ public final class ParcelableKeyGenParameterSpecTest { .setUniqueIdIncluded(true) .setUserAuthenticationValidWhileOnBody(true) .setInvalidatedByBiometricEnrollment(true) + .setIsStrongBoxBacked(true) + .setUserConfirmationRequired(true) + .setUnlockedDeviceRequired(true) .build(); } @@ -105,6 +108,9 @@ public final class ParcelableKeyGenParameterSpecTest { assertThat(spec.isUniqueIdIncluded(), is(true)); assertThat(spec.isUserAuthenticationValidWhileOnBody(), is(true)); assertThat(spec.isInvalidatedByBiometricEnrollment(), is(true)); + assertThat(spec.isStrongBoxBacked(), is(true)); + assertThat(spec.isUserConfirmationRequired(), is(true)); + assertThat(spec.isUnlockedDeviceRequired(), is(true)); } private Parcel parcelForReading(ParcelableKeyGenParameterSpec spec) { diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 0db779906545..111094bb6a2b 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -198,6 +198,7 @@ cc_defaults { "AnimatorManager.cpp", "Caches.cpp", "CanvasState.cpp", + "CanvasTransform.cpp", "ClipArea.cpp", "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp new file mode 100644 index 000000000000..bac7a4d17a49 --- /dev/null +++ b/libs/hwui/CanvasTransform.cpp @@ -0,0 +1,113 @@ +/* + * 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. + */ + +#include "CanvasTransform.h" +#include "Properties.h" + +#include <SkColorFilter.h> +#include <SkPaint.h> +#include <log/log.h> + +namespace android::uirenderer { + +static SkColor makeLight(SkColor color) { + SkScalar hsv[3]; + SkColorToHSV(color, hsv); + if (hsv[1] > .2f) return color; + // hsv[1] *= .85f; + // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f); + hsv[2] = std::max(hsv[2], 1.1f - hsv[2]); + return SkHSVToColor(SkColorGetA(color), hsv); +} + +static SkColor makeDark(SkColor color) { + SkScalar hsv[3]; + SkColorToHSV(color, hsv); + if (hsv[1] > .2f) return color; + // hsv[1] *= .85f; + // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f); + hsv[2] = std::min(hsv[2], 1.1f - hsv[2]); + return SkHSVToColor(SkColorGetA(color), hsv); +} + +static SkColor transformColor(ColorTransform transform, SkColor color) { + switch (transform) { + case ColorTransform::Light: + return makeLight(color); + case ColorTransform::Dark: + return makeDark(color); + default: + return color; + } +} + +static void applyColorTransform(ColorTransform transform, SkPaint& paint) { + if (transform == ColorTransform::None) return; + + SkColor newColor = transformColor(transform, paint.getColor()); + paint.setColor(newColor); + + if (paint.getColorFilter()) { + SkBlendMode mode; + SkColor color; + // TODO: LRU this or something to avoid spamming new color mode filters + if (paint.getColorFilter()->asColorMode(&color, &mode)) { + color = transformColor(transform, color); + paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); + } + } +} + +class ColorFilterCanvas : public SkPaintFilterCanvas { +public: + ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) + : SkPaintFilterCanvas(canvas), mTransform(transform) {} + + bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override { + if (*paint) { + applyColorTransform(mTransform, *(paint->writable())); + } + return true; + } + +private: + ColorTransform mTransform; +}; + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { + switch (transform) { + case ColorTransform::Light: + return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas); + case ColorTransform::Dark: + return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas); + default: + return nullptr; + } +} + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { + if (Properties::forceDarkMode) { + switch (usageHint) { + case UsageHint::Unknown: + return makeTransformCanvas(inCanvas, ColorTransform::Light); + case UsageHint::Background: + return makeTransformCanvas(inCanvas, ColorTransform::Dark); + } + } + return nullptr; +} + +}; // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h new file mode 100644 index 000000000000..f71fdfaf3fba --- /dev/null +++ b/libs/hwui/CanvasTransform.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#pragma once + +#include <SkCanvas.h> +#include <SkPaintFilterCanvas.h> + +#include <memory> + +namespace android::uirenderer { + +enum class UsageHint { + Unknown = 0, + Background = 1, +}; + +enum class ColorTransform { + None, + Light, + Dark, +}; + +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform); +std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint); + +} // namespace android::uirenderer;
\ No newline at end of file diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index d284269986d6..17bec1934490 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -17,6 +17,7 @@ #include "Properties.h" #include "Debug.h" #include "DeviceInfo.h" +#include "SkTraceEventCommon.h" #include <algorithm> #include <cstdlib> @@ -59,6 +60,7 @@ bool Properties::forceDrawFrame = false; bool Properties::filterOutTestOverhead = false; bool Properties::disableVsync = false; bool Properties::skpCaptureEnabled = false; +bool Properties::forceDarkMode = false; bool Properties::enableRTAnimations = true; bool Properties::runningInEmulator = false; @@ -140,8 +142,13 @@ bool Properties::load() { skpCaptureEnabled = debuggingEnabled && property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false); + SkAndroidFrameworkTraceUtil::setEnableTracing( + property_get_bool(PROPERTY_SKIA_ATRACE_ENABLED, false)); + runningInEmulator = property_get_bool(PROPERTY_QEMU_KERNEL, false); + forceDarkMode = property_get_bool(PROPERTY_FORCE_DARK, false); + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) || (prevDebugStencilClip != debugStencilClip); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 657f9aa5466e..ea017a72cd74 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -171,6 +171,11 @@ enum DebugLevel { #define PROPERTY_CAPTURE_SKP_ENABLED "debug.hwui.capture_skp_enabled" /** + * Allows to record Skia drawing commands with systrace. + */ +#define PROPERTY_SKIA_ATRACE_ENABLED "debug.hwui.skia_atrace_enabled" + +/** * Defines how many frames in a sequence to capture. */ #define PROPERTY_CAPTURE_SKP_FRAMES "debug.hwui.capture_skp_frames" @@ -185,6 +190,8 @@ enum DebugLevel { */ #define PROPERTY_QEMU_KERNEL "ro.kernel.qemu" +#define PROPERTY_FORCE_DARK "debug.hwui.force_dark" + /////////////////////////////////////////////////////////////////////////////// // Misc /////////////////////////////////////////////////////////////////////////////// @@ -258,6 +265,7 @@ public: static bool disableVsync; static bool skpCaptureEnabled; + static bool forceDarkMode; // For experimentation b/68769804 ANDROID_API static bool enableRTAnimations; diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index dc962f307903..8393288d2ffd 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -28,6 +28,7 @@ #include <androidfw/ResourceTypes.h> #include "AnimatorManager.h" +#include "CanvasTransform.h" #include "Debug.h" #include "DisplayList.h" #include "Matrix.h" @@ -208,6 +209,14 @@ public: void output(std::ostream& output, uint32_t level); + void setUsageHint(UsageHint usageHint) { + mUsageHint = usageHint; + } + + UsageHint usageHint() const { + return mUsageHint; + } + private: void computeOrderingImpl(RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface, @@ -263,6 +272,8 @@ private: sp<PositionListener> mPositionListener; + UsageHint mUsageHint = UsageHint::Unknown; + // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER public: /** diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index f0da660f17b0..6fb2ee03cb50 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -17,6 +17,7 @@ #include "SkiaRecordingCanvas.h" #include <SkImagePriv.h> +#include "CanvasTransform.h" #include "Layer.h" #include "LayerDrawable.h" #include "NinePatchUtils.h" @@ -44,13 +45,19 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in } mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); - SkiaCanvas::reset(&mRecorder); + SkCanvas* canvas = &mRecorder; + mWrappedCanvas = makeTransformCanvas(&mRecorder, renderNode->usageHint()); + if (mWrappedCanvas) { + canvas = mWrappedCanvas.get(); + } + SkiaCanvas::reset(canvas); } uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { // close any existing chunks if necessary insertReorderBarrier(false); mRecorder.restoreToCount(1); + mWrappedCanvas = nullptr; return mDisplayList.release(); } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 93807a5476e6..b69acbf2ffb8 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -78,6 +78,7 @@ public: private: SkLiteRecorder mRecorder; std::unique_ptr<SkiaDisplayList> mDisplayList; + std::unique_ptr<SkCanvas> mWrappedCanvas; StartReorderBarrierDrawable* mCurrentBarrier; /** diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index b07fb2d7ae0f..bec80b1e6011 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -134,6 +134,7 @@ void CacheManager::configureContext(GrContextOptions* contextOptions) { } contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get(); + contextOptions->fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting; } void CacheManager::trimMemory(TrimMemoryMode mode) { diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp index b74d3595e964..e3c97ce686d9 100644 --- a/libs/hwui/tests/macrobench/main.cpp +++ b/libs/hwui/tests/macrobench/main.cpp @@ -136,8 +136,6 @@ static bool setBenchmarkFormat(const char* format) { gBenchmarkReporter.reset(new benchmark::ConsoleReporter()); } else if (!strcmp(format, "json")) { gBenchmarkReporter.reset(new benchmark::JSONReporter()); - } else if (!strcmp(format, "csv")) { - gBenchmarkReporter.reset(new benchmark::CSVReporter()); } else { fprintf(stderr, "Unknown format '%s'", format); return false; diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java index 70ef81ff3f1a..b747291d1d28 100644 --- a/media/java/android/media/MediaPlayer2.java +++ b/media/java/android/media/MediaPlayer2.java @@ -883,15 +883,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener // This is a synchronous call. public abstract void clearPendingCommands(); - /** - * Stops playback after playback has been started or paused. - * - * @throws IllegalStateException if the internal player engine has not been - * initialized. - * @hide - */ - public void stop() { } - //-------------------------------------------------------------------------- // Explicit Routing //-------------------- @@ -1714,7 +1705,7 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener * @param dsd the DataSourceDesc of this data source * @param timestamp the new media clock. */ - public void onMediaTimeChanged( + public void onMediaTimeDiscontinuity( MediaPlayer2 mp, DataSourceDesc dsd, MediaTimestamp timestamp) { } /** @@ -1725,44 +1716,34 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener * {@link #notifyWhenCommandLabelReached(Object)}. */ public void onCommandLabelReached(MediaPlayer2 mp, @NonNull Object label) { } + + /** + * Called when when a player subtitle track has new subtitle data available. + * @param mp the player that reports the new subtitle data + * @param dsd the DataSourceDesc of this data source + * @param data the subtitle data + */ + public void onSubtitleData( + MediaPlayer2 mp, DataSourceDesc dsd, @NonNull SubtitleData data) { } } /** * Sets the callback to be invoked when the media source is ready for playback. * - * @param eventCallback the callback that will be run * @param executor the executor through which the callback should be invoked + * @param eventCallback the callback that will be run */ // This is a synchronous call. - public abstract void setEventCallback(@NonNull @CallbackExecutor Executor executor, + public abstract void registerEventCallback(@NonNull @CallbackExecutor Executor executor, @NonNull EventCallback eventCallback); /** - * Clears the {@link EventCallback}. - */ - // This is a synchronous call. - public abstract void clearEventCallback(); - - /** - * Interface definition of a callback to be invoked when a - * track has data available. + * Unregisters the {@link EventCallback}. * - * @hide - */ - public interface OnSubtitleDataListener - { - public void onSubtitleData(MediaPlayer2 mp, SubtitleData data); - } - - /** - * Register a callback to be invoked when a track has data available. - * - * @param listener the callback that will be run - * - * @hide + * @param eventCallback the callback to be unregistered */ // This is a synchronous call. - public void setOnSubtitleDataListener(OnSubtitleDataListener listener) { } + public abstract void unregisterEventCallback(EventCallback eventCallback); /* Do not change these values without updating their counterparts @@ -2056,11 +2037,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener */ public static final int CALL_COMPLETED_SET_PLAYBACK_PARAMS = 24; - /** The player just completed a call {@link #setPlaybackSpeed}. - * @see android.media.MediaPlayer2.EventCallback#onCallCompleted - */ - public static final int CALL_COMPLETED_SET_PLAYBACK_SPEED = 25; - /** The player just completed a call {@link #setPlayerVolume}. * @see android.media.MediaPlayer2.EventCallback#onCallCompleted */ diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java index 2b61b2e9a486..5a71afd4625e 100644 --- a/media/java/android/media/MediaPlayer2Impl.java +++ b/media/java/android/media/MediaPlayer2Impl.java @@ -97,7 +97,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private long mNativeSurfaceTexture; // accessed by native methods private int mListenerContext; // accessed by native methods private SurfaceHolder mSurfaceHolder; - private EventHandler mEventHandler; private PowerManager.WakeLock mWakeLock = null; private boolean mScreenOnWhilePlaying; private boolean mStayAwake; @@ -135,7 +134,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { //--- guarded by |mDrmLock| end private HandlerThread mHandlerThread; - private final Handler mTaskHandler; + private final TaskHandler mTaskHandler; private final Object mTaskLock = new Object(); @GuardedBy("mTaskLock") private final List<Task> mPendingTasks = new LinkedList<>(); @@ -149,19 +148,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * result in an exception.</p> */ public MediaPlayer2Impl() { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mEventHandler = new EventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mEventHandler = new EventHandler(this, looper); - } else { - mEventHandler = null; - } - mHandlerThread = new HandlerThread("MediaPlayer2TaskThread"); mHandlerThread.start(); - looper = mHandlerThread.getLooper(); - mTaskHandler = new Handler(looper); + Looper looper = mHandlerThread.getLooper(); + mTaskHandler = new TaskHandler(this, looper); mTimeProvider = new TimeProvider(this); mOpenSubtitleSources = new Vector<InputStream>(); @@ -934,13 +924,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mNextSourceState = NEXT_SOURCE_STATE_PREPARING; handleDataSource(false /* isCurrent */, mNextDSDs.get(0), mNextSrcId); } catch (Exception e) { - Message msg2 = mEventHandler.obtainMessage( + Message msg2 = mTaskHandler.obtainMessage( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null); final long nextSrcId = mNextSrcId; - mEventHandler.post(new Runnable() { + mTaskHandler.post(new Runnable() { @Override public void run() { - mEventHandler.handleMessage(msg2, nextSrcId); + mTaskHandler.handleMessage(msg2, nextSrcId); } }); } @@ -967,12 +957,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { try { nativePlayNextDataSource(srcId); } catch (Exception e) { - Message msg2 = mEventHandler.obtainMessage( + Message msg2 = mTaskHandler.obtainMessage( MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null); - mEventHandler.post(new Runnable() { + mTaskHandler.post(new Runnable() { @Override public void run() { - mEventHandler.handleMessage(msg2, srcId); + mTaskHandler.handleMessage(msg2, srcId); } }); } @@ -998,20 +988,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native int _getAudioStreamType() throws IllegalStateException; - /** - * Stops playback after playback has been started or paused. - * - * @throws IllegalStateException if the internal player engine has not been - * initialized. - * #hide - */ - @Override - public void stop() { - stayAwake(false); - _stop(); - } - - private native void _stop() throws IllegalStateException; //-------------------------------------------------------------------------- // Explicit Routing @@ -1109,7 +1085,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { enableNativeRoutingCallbacksLocked(true); mRoutingChangeListeners.put( listener, new NativeRoutingEventHandlerDelegate(this, listener, - handler != null ? handler : mEventHandler)); + handler != null ? handler : mTaskHandler)); } } } @@ -1633,8 +1609,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { stayAwake(false); _reset(); // make sure none of the listeners get called anymore - if (mEventHandler != null) { - mEventHandler.removeCallbacksAndMessages(null); + if (mTaskHandler != null) { + mTaskHandler.removeCallbacksAndMessages(null); } synchronized (mIndexTrackPairs) { @@ -2059,9 +2035,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private int mSelectedSubtitleTrackIndex = -1; private Vector<InputStream> mOpenSubtitleSources; - private OnSubtitleDataListener mSubtitleDataListener = new OnSubtitleDataListener() { + private EventCallback mSubtitleDataCallback = new EventCallback() { @Override - public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) { + public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) { int index = data.getTrackIndex(); synchronized (mIndexTrackPairs) { for (Pair<Integer, SubtitleTrack> p : mIndexTrackPairs) { @@ -2085,7 +2061,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } mSelectedSubtitleTrackIndex = -1; } - setOnSubtitleDataListener(null); + unregisterEventCallback(mSubtitleDataCallback); if (track == null) { return; } @@ -2105,7 +2081,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { selectOrDeselectInbandTrack(mSelectedSubtitleTrackIndex, true); } catch (IllegalStateException e) { } - setOnSubtitleDataListener(mSubtitleDataListener); + final Executor executor = (runnable) -> mTaskHandler.post(runnable); + registerEventCallback(executor, mSubtitleDataCallback); } // no need to select out-of-band tracks } @@ -2167,9 +2144,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { public void run() { int res = addTrack(); - if (mEventHandler != null) { - Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null); - mEventHandler.sendMessage(m); + if (mTaskHandler != null) { + Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null); + mTaskHandler.sendMessage(m); } thread.getLooper().quitSafely(); } @@ -2357,7 +2334,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { if (!mSubtitleController.hasRendererFor(fFormat)) { // test and add not atomic Context context = ActivityThread.currentApplication(); - mSubtitleController.registerRenderer(new SRTRenderer(context, mEventHandler)); + mSubtitleController.registerRenderer(new SRTRenderer(context, mTaskHandler)); } final SubtitleTrack track = mSubtitleController.addTrack(fFormat); synchronized (mIndexTrackPairs) { @@ -2410,9 +2387,9 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { public void run() { int res = addTrack(); - if (mEventHandler != null) { - Message m = mEventHandler.obtainMessage(MEDIA_INFO, res, 0, null); - mEventHandler.sendMessage(m); + if (mTaskHandler != null) { + Message m = mTaskHandler.obtainMessage(MEDIA_INFO, res, 0, null); + mTaskHandler.sendMessage(m); } thread.getLooper().quitSafely(); } @@ -2628,7 +2605,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { mTimeProvider.close(); mTimeProvider = null; } - mOnSubtitleDataListener = null; // Modular DRM clean up mOnDrmConfigHelper = null; @@ -2675,10 +2651,10 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { return mTimeProvider; } - private class EventHandler extends Handler { + private class TaskHandler extends Handler { private MediaPlayer2Impl mMediaPlayer; - public EventHandler(MediaPlayer2Impl mp, Looper looper) { + public TaskHandler(MediaPlayer2Impl mp, Looper looper) { super(looper); mMediaPlayer = mp; } @@ -2969,7 +2945,8 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { - cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, mCurrentDSD, text)); + cb.first.execute(() -> cb.second.onTimedText( + mMediaPlayer, mCurrentDSD, text)); } } return; @@ -2977,15 +2954,16 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_SUBTITLE_DATA: { - OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener; - if (onSubtitleDataListener == null) { - return; - } if (msg.obj instanceof Parcel) { Parcel parcel = (Parcel) msg.obj; SubtitleData data = new SubtitleData(parcel); parcel.recycle(); - onSubtitleDataListener.onSubtitleData(mMediaPlayer, data); + synchronized (mEventCbLock) { + for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { + cb.first.execute(() -> cb.second.onSubtitleData( + mMediaPlayer, mCurrentDSD, data)); + } + } } return; } @@ -3038,7 +3016,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { /* * Called from native code when an interesting event happens. This method - * just uses the EventHandler system to post the event back to the main app thread. + * just uses the TaskHandler system to post the event back to the main app thread. * We use a weak reference to the original MediaPlayer2 object so that the native * code is safe from the object disappearing from underneath it. (This is * the cookie passed to native_setup().) @@ -3067,7 +3045,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_DRM_INFO: // We need to derive mDrmInfoImpl before prepare() returns so processing it here - // before the notification is sent to EventHandler below. EventHandler runs in the + // before the notification is sent to TaskHandler below. TaskHandler runs in the // notification looper so its handleMessage might process the event after prepare() // has returned. Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO"); @@ -3094,13 +3072,13 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } - if (mp.mEventHandler != null) { - Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); + if (mp.mTaskHandler != null) { + Message m = mp.mTaskHandler.obtainMessage(what, arg1, arg2, obj); - mp.mEventHandler.post(new Runnable() { + mp.mTaskHandler.post(new Runnable() { @Override public void run() { - mp.mEventHandler.handleMessage(m, srcId); + mp.mTaskHandler.handleMessage(m, srcId); } }); } @@ -3118,7 +3096,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * @param executor the executor through which the callback should be invoked */ @Override - public void setEventCallback(@NonNull @CallbackExecutor Executor executor, + public void registerEventCallback(@NonNull @CallbackExecutor Executor executor, @NonNull EventCallback eventCallback) { if (eventCallback == null) { throw new IllegalArgumentException("Illegal null EventCallback"); @@ -3136,27 +3114,16 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { * Clears the {@link EventCallback}. */ @Override - public void clearEventCallback() { + public void unregisterEventCallback(EventCallback eventCallback) { synchronized (mEventCbLock) { - mEventCallbackRecords.clear(); + for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { + if (cb.second == eventCallback) { + mEventCallbackRecords.remove(cb); + } + } } } - /** - * Register a callback to be invoked when a track has data available. - * - * @param listener the callback that will be run - * - * @hide - */ - @Override - public void setOnSubtitleDataListener(OnSubtitleDataListener listener) { - mOnSubtitleDataListener = listener; - } - - private OnSubtitleDataListener mOnSubtitleDataListener; - - // Modular DRM begin /** diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 143182f83ace..ec2d9bab5107 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -888,6 +888,8 @@ public final class TvInputManager { if (token != null) { session = new Session(token, channel, mService, mUserId, seq, mSessionCallbackRecordMap); + } else { + mSessionCallbackRecordMap.delete(seq); } record.postSessionCreated(session); } @@ -2487,7 +2489,7 @@ public final class TvInputManager { } } synchronized (mSessionCallbackRecordMap) { - mSessionCallbackRecordMap.remove(mSeq); + mSessionCallbackRecordMap.delete(mSeq); } } diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp index d166cc3882a6..abf053408633 100644 --- a/media/jni/android_media_MediaPlayer2.cpp +++ b/media/jni/android_media_MediaPlayer2.cpp @@ -568,18 +568,6 @@ android_media_MediaPlayer2_start(JNIEnv *env, jobject thiz) } static void -android_media_MediaPlayer2_stop(JNIEnv *env, jobject thiz) -{ - ALOGV("stop"); - sp<MediaPlayer2> mp = getMediaPlayer(env, thiz); - if (mp == NULL ) { - jniThrowException(env, "java/lang/IllegalStateException", NULL); - return; - } - process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); -} - -static void android_media_MediaPlayer2_pause(JNIEnv *env, jobject thiz) { ALOGV("pause"); @@ -1501,7 +1489,6 @@ static const JNINativeMethod gMethods[] = { {"_setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams}, {"_prepare", "()V", (void *)android_media_MediaPlayer2_prepare}, {"_start", "()V", (void *)android_media_MediaPlayer2_start}, - {"_stop", "()V", (void *)android_media_MediaPlayer2_stop}, {"native_getState", "()I", (void *)android_media_MediaPlayer2_getState}, {"getVideoWidth", "()I", (void *)android_media_MediaPlayer2_getVideoWidth}, {"getVideoHeight", "()I", (void *)android_media_MediaPlayer2_getVideoHeight}, diff --git a/packages/SettingsLib/res/values-bs/arrays.xml b/packages/SettingsLib/res/values-bs/arrays.xml index 8577779d104c..9b3c38c0ab0c 100644 --- a/packages/SettingsLib/res/values-bs/arrays.xml +++ b/packages/SettingsLib/res/values-bs/arrays.xml @@ -27,7 +27,7 @@ <item msgid="515055375277271756">"Autentifikacija…"</item> <item msgid="1943354004029184381">"Dobivanje IP adrese…"</item> <item msgid="4221763391123233270">"Povezano"</item> - <item msgid="624838831631122137">"Suspendiran"</item> + <item msgid="624838831631122137">"Suspendirano"</item> <item msgid="7979680559596111948">"Prekidanje veze…"</item> <item msgid="1634960474403853625">"Isključen"</item> <item msgid="746097431216080650">"Neuspješno"</item> @@ -38,11 +38,11 @@ <item msgid="7714855332363650812"></item> <item msgid="8878186979715711006">"Skeniranje…"</item> <item msgid="355508996603873860">"Povezivanje na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item> - <item msgid="554971459996405634">"Autentifikacija sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> + <item msgid="554971459996405634">"Autentifikacija s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> <item msgid="7928343808033020343">"Dobivanje IP adrese iz mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> - <item msgid="8937994881315223448">"Povezan na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item> - <item msgid="1330262655415760617">"Suspendiran"</item> - <item msgid="7698638434317271902">"Prekidanje veze sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> + <item msgid="8937994881315223448">"Povezano na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item> + <item msgid="1330262655415760617">"Suspendirano"</item> + <item msgid="7698638434317271902">"Prekidanje veze s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item> <item msgid="197508606402264311">"Isključen"</item> <item msgid="8578370891960825148">"Neuspješno"</item> <item msgid="5660739516542454527">"Blokirano"</item> @@ -59,7 +59,7 @@ <item msgid="45075631231212732">"Uvijek koristi HDCP provjeru"</item> </string-array> <string-array name="bluetooth_avrcp_versions"> - <item msgid="5347678900838034763">"AVRCP 1.4 (Zadano)"</item> + <item msgid="5347678900838034763">"AVRCP 1.4 (zadano)"</item> <item msgid="2809759619990248160">"AVRCP 1.3"</item> <item msgid="6199178154704729352">"AVRCP 1.5"</item> <item msgid="5172170854953034852">"AVRCP 1.6"</item> @@ -71,58 +71,58 @@ <item msgid="3422726142222090896">"avrcp16"</item> </string-array> <string-array name="bluetooth_a2dp_codec_titles"> - <item msgid="7065842274271279580">"Koristi odabir sistema (Zadano)"</item> + <item msgid="7065842274271279580">"Koristi odabir sistema (zadano)"</item> <item msgid="7539690996561263909">"SBC"</item> <item msgid="686685526567131661">"AAC"</item> <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item> <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item> <item msgid="6751080638867012696">"LDAC"</item> - <item msgid="723675059572222462">"Omogućite opcionalne kodeke"</item> - <item msgid="3304843301758635896">"Onemogućite opcionalne kodeke"</item> + <item msgid="723675059572222462">"Omogući opcionalne kodeke"</item> + <item msgid="3304843301758635896">"Onemogući opcionalne kodeke"</item> </string-array> <string-array name="bluetooth_a2dp_codec_summaries"> - <item msgid="5062108632402595000">"Koristi odabir sistema (Zadano)"</item> + <item msgid="5062108632402595000">"Koristi odabir sistema (zadano)"</item> <item msgid="6898329690939802290">"SBC"</item> <item msgid="6839647709301342559">"AAC"</item> <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item> <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item> <item msgid="7950781694447359344">"LDAC"</item> - <item msgid="2209680154067241740">"Omogućite opcionalne kodeke"</item> - <item msgid="741805482892725657">"Onemogućite opcionalne kodeke"</item> + <item msgid="2209680154067241740">"Omogući opcionalne kodeke"</item> + <item msgid="741805482892725657">"Onemogući opcionalne kodeke"</item> </string-array> <string-array name="bluetooth_a2dp_codec_sample_rate_titles"> - <item msgid="3093023430402746802">"Koristi odabir sistema (Zadano)"</item> + <item msgid="3093023430402746802">"Koristi odabir sistema (zadano)"</item> <item msgid="8895532488906185219">"44,1 kHz"</item> <item msgid="2909915718994807056">"48,0 kHz"</item> <item msgid="3347287377354164611">"88,2 kHz"</item> <item msgid="1234212100239985373">"96,0 kHz"</item> </string-array> <string-array name="bluetooth_a2dp_codec_sample_rate_summaries"> - <item msgid="3214516120190965356">"Koristi odabir sistema (Zadano)"</item> + <item msgid="3214516120190965356">"Koristi odabir sistema (zadano)"</item> <item msgid="4482862757811638365">"44,1 kHz"</item> <item msgid="354495328188724404">"48,0 kHz"</item> <item msgid="7329816882213695083">"88,2 kHz"</item> <item msgid="6967397666254430476">"96,0 kHz"</item> </string-array> <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles"> - <item msgid="2684127272582591429">"Koristi odabir sistema (Zadano)"</item> + <item msgid="2684127272582591429">"Koristi odabir sistema (zadano)"</item> <item msgid="5618929009984956469">"16 bitova/uzorak"</item> <item msgid="3412640499234627248">"24 bitova/uzorak"</item> <item msgid="121583001492929387">"32 bitova/uzorak"</item> </string-array> <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries"> - <item msgid="1081159789834584363">"Koristi odabir sistema (Zadano)"</item> + <item msgid="1081159789834584363">"Koristi odabir sistema (zadano)"</item> <item msgid="4726688794884191540">"16 bitova/uzorak"</item> <item msgid="305344756485516870">"24 bitova/uzorak"</item> <item msgid="244568657919675099">"32 bitova/uzorak"</item> </string-array> <string-array name="bluetooth_a2dp_codec_channel_mode_titles"> - <item msgid="5226878858503393706">"Koristi odabir sistema (Zadano)"</item> + <item msgid="5226878858503393706">"Koristi odabir sistema (zadano)"</item> <item msgid="4106832974775067314">"Mono"</item> <item msgid="5571632958424639155">"Stereo"</item> </string-array> <string-array name="bluetooth_a2dp_codec_channel_mode_summaries"> - <item msgid="4118561796005528173">"Koristi odabir sistema (Zadano)"</item> + <item msgid="4118561796005528173">"Koristi odabir sistema (zadano)"</item> <item msgid="8900559293912978337">"Mono"</item> <item msgid="8883739882299884241">"Stereo"</item> </string-array> @@ -130,13 +130,13 @@ <item msgid="7158319962230727476">"Optimizirano za kvalitet zvuka (990 kbps/909 kbps)"</item> <item msgid="2921767058740704969">"Uravnotežen kvalitet zvuka i veze (660kbps/606kbps)"</item> <item msgid="8860982705384396512">"Optimizirano za kvalitet veze (330 kbps/303 kbps)"</item> - <item msgid="4414060457677684127">"Maksimalan napor (Prilagodljiva brzina prijenosa)"</item> + <item msgid="4414060457677684127">"Maksimalan napor (prilagodljiva brzina prijenosa)"</item> </string-array> <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries"> <item msgid="6398189564246596868">"Optimizirano za kvalitet zvuka"</item> <item msgid="4327143584633311908">"Uravnotežen kvalitet zvuka i veze"</item> <item msgid="4681409244565426925">"Optimizirano za kvalitet veze"</item> - <item msgid="364670732877872677">"Maksimalan napor (Prilagodljiva brzina prijenosa)"</item> + <item msgid="364670732877872677">"Maksimalan napor (prilagodljiva brzina prijenosa)"</item> </string-array> <string-array name="bluetooth_audio_active_device_summaries"> <item msgid="4862957058729193940"></item> @@ -169,7 +169,7 @@ <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Isključeno"</item> <item msgid="3054662377365844197">"Sve"</item> - <item msgid="688870735111627832">"Svi osim radija"</item> + <item msgid="688870735111627832">"Sve osim radija"</item> <item msgid="2850427388488887328">"samo kernel"</item> </string-array> <string-array name="select_logpersist_summaries"> @@ -208,13 +208,13 @@ <string-array name="overlay_display_devices_entries"> <item msgid="1606809880904982133">"Nema"</item> <item msgid="9033194758688161545">"480p"</item> - <item msgid="1025306206556583600">"480p (osiguran)"</item> + <item msgid="1025306206556583600">"480p (sigurno)"</item> <item msgid="1853913333042744661">"720p"</item> - <item msgid="3414540279805870511">"720p (osiguran)"</item> + <item msgid="3414540279805870511">"720p (sigurno)"</item> <item msgid="9039818062847141551">"1080p"</item> - <item msgid="4939496949750174834">"1080p (osiguran)"</item> + <item msgid="4939496949750174834">"1080p (sigurno)"</item> <item msgid="1833612718524903568">"4K"</item> - <item msgid="238303513127879234">"4K (osiguran)"</item> + <item msgid="238303513127879234">"4K (sigurno)"</item> <item msgid="3547211260846843098">"4K (povećava rezoluciju)"</item> <item msgid="5411365648951414254">"4K (povećava rezoluciju, osiguran)"</item> <item msgid="1311305077526792901">"720p, 1080p (dupli ekran)"</item> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index b8195b122db3..e049f6f99d18 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -43,7 +43,7 @@ <string name="wifi_status_no_internet" msgid="5784710974669608361">"Nema internetske veze"</string> <string name="wifi_status_sign_in_required" msgid="123517180404752756">"Potrebna je prijava"</string> <string name="wifi_ap_unable_to_handle_new_sta" msgid="5348824313514404541">"Pristupna tačka je privremeno puna"</string> - <string name="connected_via_carrier" msgid="7583780074526041912">"Povezana koristeći %1$s"</string> + <string name="connected_via_carrier" msgid="7583780074526041912">"Povezano koristeći %1$s"</string> <string name="available_via_carrier" msgid="1469036129740799053">"Dostupna koristeći %1$s"</string> <string name="speed_label_very_slow" msgid="1867055264243608530">"Veoma sporo"</string> <string name="speed_label_slow" msgid="813109590815810235">"Sporo"</string> @@ -84,11 +84,11 @@ <string name="bluetooth_hearing_aid_profile_summary_connected" msgid="7188282786730266159">"Povezano na slušni aparat"</string> <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string> <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano na zvuk telefona"</string> - <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezan na server za prijenos podataka"</string> + <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano sa serverom za prijenos podataka"</string> <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezano na mapu"</string> <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezan na SAP"</string> - <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezan na server za prijenos podataka"</string> - <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Spojen na ulazni uređaj"</string> + <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezano sa serverom za prijenos podataka"</string> + <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezano s ulaznim uređajem"</string> <string name="bluetooth_pan_user_profile_summary_connected" msgid="6436258151814414028">"Povezano na uređaj za pristup internetu"</string> <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1322694224800769308">"Dijeljenje lokalne internetske veze s uređajem"</string> <string name="bluetooth_pan_profile_summary_use_for" msgid="5736111170225304239">"Koristi za pristup internetu"</string> @@ -102,10 +102,10 @@ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string> <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string> - <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje odobrava pristup kontaktima i istoriji poziva kada je uspostavljeno."</string> - <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nije se moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zbog pogrešnog PIN-a ili pristupnog koda."</string> - <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ne može komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje odobrava pristup kontaktima i historiji poziva kada je uspostavljeno."</string> + <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nije moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> + <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nije moguće upariti s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> zbog pogrešnog PIN-a ili pristupnog koda."</string> + <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nije moguće komunicirati s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio uparivanje."</string> <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Računar"</string> <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Slušalice s mikrofonom"</string> @@ -118,12 +118,12 @@ <string name="bluetooth_hearingaid_right_pairing_message" msgid="1550373802309160891">"Uparivanje desnog slušnog aparata…"</string> <string name="bluetooth_hearingaid_left_battery_level" msgid="8797811465352097562">"Lijevi - <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> <string name="bluetooth_hearingaid_right_battery_level" msgid="7309476148173459677">"Desni - <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> baterije"</string> - <string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi isključen."</string> + <string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi je isključen."</string> <string name="accessibility_no_wifi" msgid="8834610636137374508">"WiFi nije povezan."</string> - <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi jedna crtica."</string> - <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WiFi dvije crtice."</string> - <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WiFi tri crtice."</string> - <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WiFi puni signal."</string> + <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi signal ima jednu crtu."</string> + <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WiFi signal ima dvije crte."</string> + <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WiFi signal ima tri crte."</string> + <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WiFi signal je pun."</string> <string name="accessibility_wifi_security_type_none" msgid="1223747559986205423">"Otvorena mreža"</string> <string name="accessibility_wifi_security_type_secured" msgid="862921720418885331">"Sigurna mreža"</string> <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string> @@ -132,7 +132,7 @@ <string name="tether_settings_title_usb" msgid="6688416425801386511">"Povezivanje mobitela USB-om"</string> <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prijenosna pristupna tačka"</string> <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetooth veze"</string> - <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Dijeljenje veze"</string> + <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Povezivanje putem mobitela"</string> <string name="tether_settings_title_all" msgid="8356136101061143841">"Povezivanje putem mobitela i prijenosna pristupna tačka"</string> <string name="managed_user_title" msgid="8109605045406748842">"Sve radne aplikacije"</string> <string name="user_guest" msgid="8475274842845401871">"Gost"</string> @@ -145,7 +145,7 @@ <string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina kojom se izgovara tekst"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"Visina"</string> - <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utječe na ton sintetiziranog govora"</string> + <string name="tts_default_pitch_summary" msgid="1944885882882650009">"Utiče na ton sintetiziranog govora"</string> <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string> <string name="tts_lang_use_system" msgid="2679252467416513208">"Korištenje sistemskog jezika"</string> <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string> @@ -187,7 +187,7 @@ <string name="development_settings_summary" msgid="1815795401632854041">"Postavi opcije za razvoj aplikacija"</string> <string name="development_settings_not_available" msgid="4308569041701535607">"Opcije za programere nisu dostupne za ovog korisnika"</string> <string name="vpn_settings_not_available" msgid="956841430176985598">"VPN postavke nisu dostupne za ovog korisnika"</string> - <string name="tethering_settings_not_available" msgid="6765770438438291012">"Postavke za privezivanje nisu dostupne za ovog korisnika"</string> + <string name="tethering_settings_not_available" msgid="6765770438438291012">"Postavke za povezivanje putem mobitela nisu dostupne za ovog korisnika"</string> <string name="apn_settings_not_available" msgid="7873729032165324000">"Postavke za ime pristupne tačke nisu dostupne za ovog korisnika"</string> <string name="enable_adb" msgid="7982306934419797485">"Otklanjanje grešaka putem uređaja spojenog na USB"</string> <string name="enable_adb_summary" msgid="4881186971746056635">"Način rada za uklanjanje grešaka kada je povezan USB"</string> @@ -201,7 +201,7 @@ <string name="oem_unlock_enable" msgid="6040763321967327691">"OEM otključavanje"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Dozvoli otključavanje bootloadera"</string> <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Želite li dozvoliti OEM otključavanje?"</string> - <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"UPOZORENJE: Funkcije zaštite ovog uređaja neće funkcionisati dok je ova postavka uključena."</string> + <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"UPOZORENJE: Funkcije zaštite ovog uređaja neće funkcionirati dok je ova postavka uključena."</string> <string name="mock_location_app" msgid="7966220972812881854">"Odaberite aplikaciju za lažne lokacije"</string> <string name="mock_location_app_not_set" msgid="809543285495344223">"Aplikacija za lažnu lokaciju nije postavljena"</string> <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažne lokacije: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> @@ -210,7 +210,7 @@ <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljniju evidenciju za WiFi"</string> <string name="wifi_connected_mac_randomization" msgid="3168165236877957767">"Nasumični odabir MAC adrese pri povezivanju"</string> <string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna mreža za prijenos podataka je uvijek aktivna"</string> - <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje dijeljenja veze"</string> + <string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje za povezivanje putem mobitela"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Prikaži Bluetooth uređaje bez naziva"</string> <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu jačinu zvuka"</string> <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP verzija"</string> @@ -220,7 +220,7 @@ <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Brzina uzorkovanja za Bluetooth audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Aktivirajte Bluetooth Audio Codec\nOdabir: Brzina uzorkovanja"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bluetooth audio bitovi po uzorku"</string> - <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Aktivirajte Bluetooth Audio Codec\nOdabir: Bitovi po semplu"</string> + <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Aktivirajte Bluetooth Audio Codec\nOdabir: Bitovi po uzorku"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Način Bluetooth audio kanala"</string> <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="7234956835280563341">"Aktivirajte Bluetooth Audio Codec\nOdabir: Način rada po kanalima"</string> <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3619694372407843405">"Bluetooth Audio LDAC kodek: Kvalitet reprodukcije"</string> @@ -249,7 +249,7 @@ <string name="allow_mock_location" msgid="2787962564578664888">"Dozvoli lažne lokacije"</string> <string name="allow_mock_location_summary" msgid="317615105156345626">"Dozvoli lažne lokacije"</string> <string name="debug_view_attributes" msgid="6485448367803310384">"Omogući pregled atributa prikaza"</string> - <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži prijenos podataka na mobilnoj mreži aktivnim, čak i kada je WiFi je aktivan (za brzo prebacivanje između mreža)."</string> + <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Uvijek drži prijenos podataka na mobilnoj mreži aktivnim, čak i kada je WiFi aktivan (za brzo prebacivanje između mreža)."</string> <string name="tethering_hardware_offload_summary" msgid="7726082075333346982">"Koristi hardversko ubrzavanje dijeljenja veze, ako je dostupno"</string> <string name="adb_warning_title" msgid="6234463310896563253">"Omogućiti otklanjanje grešaka putem uređaja spojenog na USB?"</string> <string name="adb_warning_message" msgid="7316799925425402244">"Otklanjanje grešaka putem uređaja spojenog na USB je namijenjeno samo u svrhe razvoja aplikacija. Koristite ga za kopiranje podataka između računara i uređaja, instaliranje aplikacija na uređaj bez obavještenja te čitanje podataka iz zapisnika."</string> @@ -277,7 +277,7 @@ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Prikaz s hardverskom akceleracijom"</string> <string name="media_category" msgid="4388305075496848353">"Mediji"</string> <string name="debug_monitoring_category" msgid="7640508148375798343">"Praćenje"</string> - <string name="strict_mode" msgid="1938795874357830695">"Omogućen strogi režim"</string> + <string name="strict_mode" msgid="1938795874357830695">"Omogućen strogi način rada"</string> <string name="strict_mode_summary" msgid="142834318897332338">"Prikaži ekran uz treptanje kada aplikacije vrše duge operacije u glavnoj niti"</string> <string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string> <string name="pointer_location_summary" msgid="840819275172753713">"Trenutni podaci o dodirivanju prikazuju se u nadsloju preko ekrana"</string> @@ -298,8 +298,8 @@ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Onemogući autom. usmjerav. na USB audio periferije"</string> <string name="debug_layout" msgid="5981361776594526155">"Prikaži granice rasporeda"</string> <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice isječka, margine itd."</string> - <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna u lijevo"</string> - <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna u lijevo za sve regije"</string> + <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna ulijevo"</string> + <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna ulijevo za sve regije"</string> <string name="force_msaa" msgid="7920323238677284387">"Prinudno primijeni 4x MSAA"</string> <string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string> <string name="show_non_rect_clip" msgid="505954950474595172">"Ispravi greške na nepravougaonim operacijama isjecanja"</string> @@ -321,19 +321,19 @@ <string name="force_allow_on_external" msgid="3215759785081916381">"Nametni aplikacije na vanjskoj pohrani"</string> <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Omogućava upisivanje svih aplikacija u vanjsku pohranu, bez obzira na prikazane vrijednosti"</string> <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni aktivnostima mijenjanje veličina"</string> - <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za prikaz sa više prozora, bez obzira na prikazane vrijednosti."</string> + <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Omogući mijenjanje veličine svih aktivnosti za prikaz s više prozora, bez obzira na prikazane vrijednosti."</string> <string name="enable_freeform_support" msgid="1461893351278940416">"Omogući prozore nepravilnih oblika"</string> <string name="enable_freeform_support_summary" msgid="8247310463288834487">"Omogući podršku za eksperimentalne prozore nepravilnih oblika."</string> <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka za sigurnosnu kopiju radne površine"</string> <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije za računare trenutno nisu zaštićene"</string> - <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije sa radne površine"</string> - <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju postavljena"</string> + <string name="local_backup_password_summary_change" msgid="5376206246809190364">"Dodirnite da promijenite ili uklonite lozinku za potpune rezervne kopije s radne površine"</string> + <string name="local_backup_password_toast_success" msgid="582016086228434290">"Nova lozinka za sigurnosnu kopiju je postavljena"</string> <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i potvrda se ne podudaraju"</string> <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Nije uspjelo postavljanje lozinke za sigurnosnu kopiju"</string> <string-array name="color_mode_names"> - <item msgid="2425514299220523812">"Živopisan (zadano)"</item> + <item msgid="2425514299220523812">"Živopisno (zadano)"</item> <item msgid="8446070607501413455">"Prirodan"</item> - <item msgid="6553408765810699025">"Standardni"</item> + <item msgid="6553408765810699025">"Standardno"</item> </string-array> <string-array name="color_mode_descriptions"> <item msgid="4979629397075120893">"Unaprijeđene boje"</item> @@ -353,9 +353,9 @@ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvaranje…"</string> <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fajl je već šifriran"</string> <string name="title_convert_fbe" msgid="1263622876196444453">"Pretvaranje u šifrirane fajlove"</string> - <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Pretvorite particiju sa podacima u particiju šifriranu sistemom fajlova.\n !! Upozorenje!! Ovo će izbrisati sve vaše podatke.\n Ova funkcija je u alfa fazi razvoja i možda neće ispravno raditi.\n Pritisnite \"Obriši i pretvori…\" da nastavite."</string> + <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Pretvorite particiju s podacima u particiju šifriranu sistemom fajlova.\n !! Upozorenje!! Ovo će izbrisati sve vaše podatke.\n Ova funkcija je u alfa fazi razvoja i možda neće ispravno raditi.\n Pritisnite \"Obriši i pretvori…\" da nastavite."</string> <string name="button_convert_fbe" msgid="5152671181309826405">"Obriši i pretvori…"</string> - <string name="picture_color_mode" msgid="4560755008730283695">"Režim boja Slika"</string> + <string name="picture_color_mode" msgid="4560755008730283695">"Način rada boja slika"</string> <string name="picture_color_mode_desc" msgid="1141891467675548590">"Koristi sRGB"</string> <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Onemogućeno"</string> <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"Crno-bijelo"</string> @@ -422,8 +422,8 @@ <string name="retail_demo_reset_title" msgid="696589204029930100">"Potrebna je lozinka"</string> <string name="active_input_method_subtypes" msgid="3596398805424733238">"Aktivne metode unosa"</string> <string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"Koristi jezik sistema"</string> - <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Nije uspjelo otvaranje postavki za <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g>"</string> - <string name="ime_security_warning" msgid="4135828934735934248">"Ovaj način unosa može prikupiti sav tekst koji otkucate, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Način omogućava aplikacija <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Da li želite koristiti ovaj način unosa?"</string> + <string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"Otvaranje postavki za <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> nije uspjelo"</string> + <string name="ime_security_warning" msgid="4135828934735934248">"Ovaj način unosa može prikupiti sav tekst koji upišete, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. Način omogućava aplikacija <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Da li želite koristiti ovaj način unosa?"</string> <string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"Napomena: Nakon ponovnog pokretanja, ova aplikacija se neće moći pokrenuti dok ne otključate telefon"</string> <string name="ims_reg_title" msgid="7609782759207241443">"Stanje IMS registracije"</string> <string name="ims_reg_status_registered" msgid="933003316932739188">"Registrirano"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index e9b07a49355d..f04767b72b78 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -217,8 +217,8 @@ <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona la versión AVRCP del Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio de Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="8436224899475822557">"Activar el códec de audio por Bluetooth\nSelección"</string> - <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Porcentaje de muestreo de audio por Bluetooth"</string> - <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Activar el códec de audio por Bluetooth\nSelección: porcentaje de muestreo"</string> + <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de muestreo de audio por Bluetooth"</string> + <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="8010380028880963535">"Activar el códec de audio por Bluetooth\nSelección: frecuencia de muestreo"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por muestra del audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="8063859754619484760">"Activar el códec de audio por Bluetooth\nSelección: bits por muestra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal de audio por Bluetooth"</string> @@ -238,7 +238,7 @@ <string name="wifi_connected_mac_randomization_summary" msgid="1743059848752201485">"Ordenar las direcciones MAC de forma aleatoria al conectarse a redes Wi‑Fi"</string> <string name="wifi_metered_label" msgid="4514924227256839725">"Medida"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"No medida"</string> - <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños de búfer de registrador"</string> + <string name="select_logd_size_title" msgid="7433137108348553508">"Tamaños del búfer para registrar"</string> <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Elige el tamaño del Logger por búfer"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"¿Borrar almacenamiento continuo del registrador?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Cuando ya no supervisamos la actividad con el registrador de forma continua, estamos obligados a borrar los datos del registrador almacenados en el dispositivo."</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 7dfd429f0646..447ce3cf6172 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -159,7 +159,7 @@ <string name="tts_default_sample_string" msgid="4040835213373086322">"این نمونهای از ترکیب گفتار است"</string> <string name="tts_status_title" msgid="7268566550242584413">"وضعیت زبان پیشفرض"</string> <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> کاملاً پشتیبانی میشود"</string> - <string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> به اتصال شبکه نیاز دارد"</string> + <string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> باید اتصال شبکه داشته باشد"</string> <string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> پشتیبانی نمیشود"</string> <string name="tts_status_checking" msgid="5339150797940483592">"در حال بررسی…"</string> <string name="tts_engine_settings_title" msgid="3499112142425680334">"تنظیمات برای <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string> diff --git a/packages/SettingsLib/res/values-gl/arrays.xml b/packages/SettingsLib/res/values-gl/arrays.xml index c6c4a2ef2ff3..f8a69c210d80 100644 --- a/packages/SettingsLib/res/values-gl/arrays.xml +++ b/packages/SettingsLib/res/values-gl/arrays.xml @@ -207,12 +207,12 @@ </string-array> <string-array name="overlay_display_devices_entries"> <item msgid="1606809880904982133">"Ningunha"</item> - <item msgid="9033194758688161545">"480 p"</item> - <item msgid="1025306206556583600">"480 p (seguro)"</item> + <item msgid="9033194758688161545">"480p"</item> + <item msgid="1025306206556583600">"480p (seguro)"</item> <item msgid="1853913333042744661">"720p"</item> <item msgid="3414540279805870511">"720p (seguro)"</item> - <item msgid="9039818062847141551">"1080 p"</item> - <item msgid="4939496949750174834">"1080 p (seguro)"</item> + <item msgid="9039818062847141551">"1080p"</item> + <item msgid="4939496949750174834">"1080p (seguro)"</item> <item msgid="1833612718524903568">"4K"</item> <item msgid="238303513127879234">"4K (seguro)"</item> <item msgid="3547211260846843098">"4K (mellorado)"</item> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 4f26f6afea25..3e55dc3f93bc 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -110,7 +110,7 @@ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Ordenador"</string> <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auriculares con micrófono"</string> <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Teléfono"</string> - <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imaxes"</string> + <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Dispositivo de imaxe"</string> <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auriculares"</string> <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférico de entrada"</string> <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string> @@ -213,8 +213,8 @@ <string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware para conexión compartida"</string> <string name="bluetooth_show_devices_without_names" msgid="4708446092962060176">"Mostrar dispositivos Bluetooth sen nomes"</string> <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactivar volume absoluto"</string> - <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP de Bluetooth"</string> - <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona a versión AVRCP de Bluetooth"</string> + <string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión de Bluetooth AVRCP"</string> + <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7277329668298705702">"Selecciona a versión de Bluetooth AVRCP"</string> <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec de audio por Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="8436224899475822557">"Activar códec de audio por Bluetooth\nSelección"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de mostraxe de audio por Bluetooth"</string> @@ -353,8 +353,8 @@ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string> <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Xa se encriptou o ficheiro"</string> <string name="title_convert_fbe" msgid="1263622876196444453">"Convertendo no encriptado baseado en ficheiros"</string> - <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Converte a partición de datos nunha encriptación baseada en ficheiros.\n Advertencia: Esta acción borrará todos os datos.\n Esta función é alfa e quizais non funcione correctamente.\n Para continuar, toca Limpar e converter..."</string> - <string name="button_convert_fbe" msgid="5152671181309826405">"Limpar e converter..."</string> + <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Converte a partición de datos nunha encriptación baseada en ficheiros.\n Advertencia: Esta acción borrará todos os datos.\n Esta función é alfa e quizais non funcione correctamente.\n Para continuar, toca Borrar e converter..."</string> + <string name="button_convert_fbe" msgid="5152671181309826405">"Borrar e converter..."</string> <string name="picture_color_mode" msgid="4560755008730283695">"Modo de cor da imaxe"</string> <string name="picture_color_mode_desc" msgid="1141891467675548590">"Utiliza sRGB"</string> <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Desactivado"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 2c43d339bdac..b2a6bd003f06 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -141,7 +141,7 @@ <string name="launch_defaults_some" msgid="313159469856372621">"一部デフォルトで設定"</string> <string name="launch_defaults_none" msgid="4241129108140034876">"デフォルトの設定なし"</string> <string name="tts_settings" msgid="8186971894801348327">"テキスト読み上げの設定"</string> - <string name="tts_settings_title" msgid="1237820681016639683">"テキスト読み上げの出力"</string> + <string name="tts_settings_title" msgid="1237820681016639683">"テキスト読み上げの設定"</string> <string name="tts_default_rate_title" msgid="6030550998379310088">"音声の速度"</string> <string name="tts_default_rate_summary" msgid="4061815292287182801">"テキストの読み上げ速度"</string> <string name="tts_default_pitch_title" msgid="6135942113172488671">"音の高さ"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 7f9f4a640828..a3293e5ba400 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -307,7 +307,7 @@ <string name="enable_gpu_debug_layers" msgid="3848838293793255097">"Slå på GPU-feilsøkingslag"</string> <string name="enable_gpu_debug_layers_summary" msgid="8009136940671194940">"Tillat GPU-feilsøkingslag for feilsøkingsapper"</string> <string name="window_animation_scale_title" msgid="6162587588166114700">"Animasjonsskala for vindu"</string> - <string name="transition_animation_scale_title" msgid="387527540523595875">"Overgangsanimasjonsskala"</string> + <string name="transition_animation_scale_title" msgid="387527540523595875">"Animasjonsskala for overgang"</string> <string name="animator_duration_scale_title" msgid="3406722410819934083">"Varighetsskala for animasjon"</string> <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simulering av sekundærskjermer"</string> <string name="debug_applications_category" msgid="4206913653849771549">"Apper"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 7ec97b568a9a..e472b15c92f2 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -194,7 +194,7 @@ <string name="clear_adb_keys" msgid="4038889221503122743">"Odwołaj dostęp do debugowania USB"</string> <string name="bugreport_in_power" msgid="7923901846375587241">"Skrót do zgłoszenia błędu"</string> <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Pokaż w menu zasilania przycisk zgłaszania błędu"</string> - <string name="keep_screen_on" msgid="1146389631208760344">"Pozostaw ekran włączony"</string> + <string name="keep_screen_on" msgid="1146389631208760344">"Pozostaw włączony ekran"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"Ekran nie będzie gaszony podczas ładowania telefonu"</string> <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Włącz dziennik snoop Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Przechwyć wszystkie pakiety Bluetooth HCI do pliku (przełącz Bluetooth po zmianie tego ustawienia)"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml index dfdc09c2cb1b..563698a42da8 100644 --- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml +++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml @@ -160,11 +160,11 @@ </string-array> <string-array name="select_logd_size_summaries"> <item msgid="6921048829791179331">"Desativado"</item> - <item msgid="2969458029344750262">"64 K/buffer de log"</item> - <item msgid="1342285115665698168">"256 K/buffer de log"</item> - <item msgid="1314234299552254621">"1 M/buffer de log"</item> - <item msgid="3606047780792894151">"4 M/buffer de log"</item> - <item msgid="5431354956856655120">"16 M/buffer de log"</item> + <item msgid="2969458029344750262">"64 K/buffer de registro"</item> + <item msgid="1342285115665698168">"256 K/buffer de registro"</item> + <item msgid="1314234299552254621">"1 M/buffer de registro"</item> + <item msgid="3606047780792894151">"4 M/buffer de registro"</item> + <item msgid="5431354956856655120">"16 M/buffer de registro"</item> </string-array> <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Desativado"</item> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index dd623d0c5f64..98b877bee5e7 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -196,7 +196,7 @@ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em suspensão enquanto estiver carregando."</string> - <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar log de rastreamento Bluetooth HCI"</string> + <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar registro de rastreamento Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Capturar todos os pacotes Bluetooth HCI em um arquivo (ative o Bluetooth depois de alterar esta configuração)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueio de OEM"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Permitir que o bootloader seja desbloqueado"</string> @@ -239,7 +239,7 @@ <string name="wifi_metered_label" msgid="4514924227256839725">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Ilimitada"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> - <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de log"</string> + <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de registro"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Limpar armazenamento de logger constante?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Quando não estivermos mais monitorando com o logger constante, devemos limpar o residente de dados de logger do seu dispositivo."</string> <string name="select_logpersist_title" msgid="7530031344550073166">"Armazenar dados de logger constantemente no dispositivo"</string> diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml index dfdc09c2cb1b..563698a42da8 100644 --- a/packages/SettingsLib/res/values-pt/arrays.xml +++ b/packages/SettingsLib/res/values-pt/arrays.xml @@ -160,11 +160,11 @@ </string-array> <string-array name="select_logd_size_summaries"> <item msgid="6921048829791179331">"Desativado"</item> - <item msgid="2969458029344750262">"64 K/buffer de log"</item> - <item msgid="1342285115665698168">"256 K/buffer de log"</item> - <item msgid="1314234299552254621">"1 M/buffer de log"</item> - <item msgid="3606047780792894151">"4 M/buffer de log"</item> - <item msgid="5431354956856655120">"16 M/buffer de log"</item> + <item msgid="2969458029344750262">"64 K/buffer de registro"</item> + <item msgid="1342285115665698168">"256 K/buffer de registro"</item> + <item msgid="1314234299552254621">"1 M/buffer de registro"</item> + <item msgid="3606047780792894151">"4 M/buffer de registro"</item> + <item msgid="5431354956856655120">"16 M/buffer de registro"</item> </string-array> <string-array name="select_logpersist_titles"> <item msgid="1744840221860799971">"Desativado"</item> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index dd623d0c5f64..98b877bee5e7 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -196,7 +196,7 @@ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Mostrar um botão para gerar relatórios de bugs no menu do botão liga/desliga"</string> <string name="keep_screen_on" msgid="1146389631208760344">"Permanecer ativo"</string> <string name="keep_screen_on_summary" msgid="2173114350754293009">"A tela nunca entrará em suspensão enquanto estiver carregando."</string> - <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar log de rastreamento Bluetooth HCI"</string> + <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Ativar registro de rastreamento Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="366083475849911315">"Capturar todos os pacotes Bluetooth HCI em um arquivo (ative o Bluetooth depois de alterar esta configuração)"</string> <string name="oem_unlock_enable" msgid="6040763321967327691">"Desbloqueio de OEM"</string> <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Permitir que o bootloader seja desbloqueado"</string> @@ -239,7 +239,7 @@ <string name="wifi_metered_label" msgid="4514924227256839725">"Limitada"</string> <string name="wifi_unmetered_label" msgid="6124098729457992931">"Ilimitada"</string> <string name="select_logd_size_title" msgid="7433137108348553508">"Tamanhos de buffer de logger"</string> - <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de log"</string> + <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Sel. tam. de logger/buffer de registro"</string> <string name="dev_logpersist_clear_warning_title" msgid="684806692440237967">"Limpar armazenamento de logger constante?"</string> <string name="dev_logpersist_clear_warning_message" msgid="2256582531342994562">"Quando não estivermos mais monitorando com o logger constante, devemos limpar o residente de dados de logger do seu dispositivo."</string> <string name="select_logpersist_title" msgid="7530031344550073166">"Armazenar dados de logger constantemente no dispositivo"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreferenceCompat.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreferenceCompat.java new file mode 100644 index 000000000000..6ac9d4e21f40 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreferenceCompat.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settingslib; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.View; + +import androidx.appcompat.app.AlertDialog; +import androidx.preference.DialogPreference; +import androidx.preference.PreferenceDialogFragmentCompat; + +public class CustomDialogPreferenceCompat extends DialogPreference { + + private CustomPreferenceDialogFragment mFragment; + private DialogInterface.OnShowListener mOnShowListener; + + public CustomDialogPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public CustomDialogPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public CustomDialogPreferenceCompat(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomDialogPreferenceCompat(Context context) { + super(context); + } + + public boolean isDialogOpen() { + return getDialog() != null && getDialog().isShowing(); + } + + public Dialog getDialog() { + return mFragment != null ? mFragment.getDialog() : null; + } + + public void setOnShowListener(DialogInterface.OnShowListener listner) { + mOnShowListener = listner; + } + + protected void onPrepareDialogBuilder(AlertDialog.Builder builder, + DialogInterface.OnClickListener listener) { + } + + protected void onDialogClosed(boolean positiveResult) { + } + + protected void onClick(DialogInterface dialog, int which) { + } + + protected void onBindDialogView(View view) { + } + + private void setFragment(CustomPreferenceDialogFragment fragment) { + mFragment = fragment; + } + + private DialogInterface.OnShowListener getOnShowListener() { + return mOnShowListener; + } + + public static class CustomPreferenceDialogFragment extends PreferenceDialogFragmentCompat { + + public static CustomPreferenceDialogFragment newInstance(String key) { + final CustomPreferenceDialogFragment fragment = new CustomPreferenceDialogFragment(); + final Bundle b = new Bundle(1); + b.putString(ARG_KEY, key); + fragment.setArguments(b); + return fragment; + } + + private CustomDialogPreferenceCompat getCustomizablePreference() { + return (CustomDialogPreferenceCompat) getPreference(); + } + + @Override + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + super.onPrepareDialogBuilder(builder); + getCustomizablePreference().setFragment(this); + getCustomizablePreference().onPrepareDialogBuilder(builder, this); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + getCustomizablePreference().onDialogClosed(positiveResult); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + getCustomizablePreference().onBindDialogView(view); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Dialog dialog = super.onCreateDialog(savedInstanceState); + dialog.setOnShowListener(getCustomizablePreference().getOnShowListener()); + return dialog; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + super.onClick(dialog, which); + getCustomizablePreference().onClick(dialog, which); + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreferenceCompat.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreferenceCompat.java new file mode 100644 index 000000000000..6ddc89af03ad --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreferenceCompat.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settingslib; + +import static android.text.InputType.TYPE_CLASS_TEXT; +import static android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES; + +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.View; +import android.widget.EditText; + +import androidx.annotation.CallSuper; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.EditTextPreference; +import androidx.preference.EditTextPreferenceDialogFragmentCompat; + +public class CustomEditTextPreferenceCompat extends EditTextPreference { + + private CustomPreferenceDialogFragment mFragment; + + public CustomEditTextPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public CustomEditTextPreferenceCompat(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public CustomEditTextPreferenceCompat(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CustomEditTextPreferenceCompat(Context context) { + super(context); + } + + public EditText getEditText() { + if (mFragment != null) { + final Dialog dialog = mFragment.getDialog(); + if (dialog != null) { + return (EditText) dialog.findViewById(android.R.id.edit); + } + } + return null; + } + + public boolean isDialogOpen() { + return getDialog() != null && getDialog().isShowing(); + } + + public Dialog getDialog() { + return mFragment != null ? mFragment.getDialog() : null; + } + + protected void onPrepareDialogBuilder(AlertDialog.Builder builder, + DialogInterface.OnClickListener listener) { + } + + protected void onDialogClosed(boolean positiveResult) { + } + + protected void onClick(DialogInterface dialog, int which) { + } + + @CallSuper + protected void onBindDialogView(View view) { + final EditText editText = view.findViewById(android.R.id.edit); + if (editText != null) { + editText.setInputType(TYPE_CLASS_TEXT | TYPE_TEXT_FLAG_CAP_SENTENCES); + editText.requestFocus(); + } + } + + private void setFragment(CustomPreferenceDialogFragment fragment) { + mFragment = fragment; + } + + public static class CustomPreferenceDialogFragment extends + EditTextPreferenceDialogFragmentCompat { + + public static CustomPreferenceDialogFragment newInstance(String key) { + final CustomPreferenceDialogFragment fragment = new CustomPreferenceDialogFragment(); + final Bundle b = new Bundle(1); + b.putString(ARG_KEY, key); + fragment.setArguments(b); + return fragment; + } + + private CustomEditTextPreferenceCompat getCustomizablePreference() { + return (CustomEditTextPreferenceCompat) getPreference(); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + getCustomizablePreference().onBindDialogView(view); + } + + @Override + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + super.onPrepareDialogBuilder(builder); + getCustomizablePreference().setFragment(this); + getCustomizablePreference().onPrepareDialogBuilder(builder, this); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + getCustomizablePreference().onDialogClosed(positiveResult); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + super.onClick(dialog, which); + getCustomizablePreference().onClick(dialog, which); + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index 8a1c4ef2d81f..94efc71e6467 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -16,6 +16,7 @@ package com.android.settingslib.fuelgauge; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -90,6 +91,13 @@ public class PowerWhitelistBackend { if (TextUtils.equals(pkg, defaultDialer)) { return true; } + + final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService( + DevicePolicyManager.class); + if (devicePolicyManager.packageHasActiveAdmins(pkg)) { + return true; + } + return false; } diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java new file mode 100644 index 000000000000..ad1368c7731d --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settingslib.inputmethod; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.text.TextUtils; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.settingslib.R; + +import java.text.Collator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + +public class InputMethodAndSubtypeEnablerManagerCompat implements + Preference.OnPreferenceChangeListener { + + private final PreferenceFragmentCompat mFragment; + + private boolean mHaveHardKeyboard; + private final HashMap<String, List<Preference>> mInputMethodAndSubtypePrefsMap = + new HashMap<>(); + private final HashMap<String, TwoStatePreference> mAutoSelectionPrefsMap = new HashMap<>(); + private InputMethodManager mImm; + // TODO: Change mInputMethodInfoList to Map + private List<InputMethodInfo> mInputMethodInfoList; + private final Collator mCollator = Collator.getInstance(); + + public InputMethodAndSubtypeEnablerManagerCompat(PreferenceFragmentCompat fragment) { + mFragment = fragment; + mImm = fragment.getContext().getSystemService(InputMethodManager.class); + + mInputMethodInfoList = mImm.getInputMethodList(); + } + + public void init(PreferenceFragmentCompat fragment, String targetImi, PreferenceScreen root) { + final Configuration config = fragment.getResources().getConfiguration(); + mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY); + + for (final InputMethodInfo imi : mInputMethodInfoList) { + // Add subtype preferences of this IME when it is specified or no IME is specified. + if (imi.getId().equals(targetImi) || TextUtils.isEmpty(targetImi)) { + addInputMethodSubtypePreferences(fragment, imi, root); + } + } + } + + public void refresh(Context context, PreferenceFragmentCompat fragment) { + // Refresh internal states in mInputMethodSettingValues to keep the latest + // "InputMethodInfo"s and "InputMethodSubtype"s + InputMethodSettingValuesWrapper + .getInstance(context).refreshAllInputMethodAndSubtypes(); + InputMethodAndSubtypeUtilCompat.loadInputMethodSubtypeList(fragment, + context.getContentResolver(), mInputMethodInfoList, mInputMethodAndSubtypePrefsMap); + updateAutoSelectionPreferences(); + } + + public void save(Context context, PreferenceFragmentCompat fragment) { + InputMethodAndSubtypeUtilCompat.saveInputMethodSubtypeList(fragment, + context.getContentResolver(), mInputMethodInfoList, mHaveHardKeyboard); + } + + @Override + public boolean onPreferenceChange(final Preference pref, final Object newValue) { + if (!(newValue instanceof Boolean)) { + return true; // Invoke default behavior. + } + final boolean isChecking = (Boolean) newValue; + for (final String imiId : mAutoSelectionPrefsMap.keySet()) { + // An auto select subtype preference is changing. + if (mAutoSelectionPrefsMap.get(imiId) == pref) { + final TwoStatePreference autoSelectionPref = (TwoStatePreference) pref; + autoSelectionPref.setChecked(isChecking); + // Enable or disable subtypes depending on the auto selection preference. + setAutoSelectionSubtypesEnabled(imiId, autoSelectionPref.isChecked()); + return false; + } + } + // A subtype preference is changing. + if (pref instanceof InputMethodSubtypePreference) { + final InputMethodSubtypePreference subtypePref = (InputMethodSubtypePreference) pref; + subtypePref.setChecked(isChecking); + if (!subtypePref.isChecked()) { + // It takes care of the case where no subtypes are explicitly enabled then the auto + // selection preference is going to be checked. + updateAutoSelectionPreferences(); + } + return false; + } + return true; // Invoke default behavior. + } + + private void addInputMethodSubtypePreferences(PreferenceFragmentCompat fragment, + InputMethodInfo imi, final PreferenceScreen root) { + Context prefContext = fragment.getPreferenceManager().getContext(); + + final int subtypeCount = imi.getSubtypeCount(); + if (subtypeCount <= 1) { + return; + } + final String imiId = imi.getId(); + final PreferenceCategory keyboardSettingsCategory = + new PreferenceCategory(prefContext); + root.addPreference(keyboardSettingsCategory); + final PackageManager pm = prefContext.getPackageManager(); + final CharSequence label = imi.loadLabel(pm); + + keyboardSettingsCategory.setTitle(label); + keyboardSettingsCategory.setKey(imiId); + // TODO: Use toggle Preference if images are ready. + final TwoStatePreference autoSelectionPref = + new SwitchWithNoTextPreference(prefContext); + mAutoSelectionPrefsMap.put(imiId, autoSelectionPref); + keyboardSettingsCategory.addPreference(autoSelectionPref); + autoSelectionPref.setOnPreferenceChangeListener(this); + + final PreferenceCategory activeInputMethodsCategory = + new PreferenceCategory(prefContext); + activeInputMethodsCategory.setTitle(R.string.active_input_method_subtypes); + root.addPreference(activeInputMethodsCategory); + + CharSequence autoSubtypeLabel = null; + final ArrayList<Preference> subtypePreferences = new ArrayList<>(); + for (int index = 0; index < subtypeCount; ++index) { + final InputMethodSubtype subtype = imi.getSubtypeAt(index); + if (subtype.overridesImplicitlyEnabledSubtype()) { + if (autoSubtypeLabel == null) { + autoSubtypeLabel = InputMethodAndSubtypeUtil.getSubtypeLocaleNameAsSentence( + subtype, prefContext, imi); + } + } else { + final Preference subtypePref = new InputMethodSubtypePreference( + prefContext, subtype, imi); + subtypePreferences.add(subtypePref); + } + } + subtypePreferences.sort((lhs, rhs) -> { + if (lhs instanceof InputMethodSubtypePreference) { + return ((InputMethodSubtypePreference) lhs).compareTo(rhs, mCollator); + } + return lhs.compareTo(rhs); + }); + for (final Preference pref : subtypePreferences) { + activeInputMethodsCategory.addPreference(pref); + pref.setOnPreferenceChangeListener(this); + InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref); + } + mInputMethodAndSubtypePrefsMap.put(imiId, subtypePreferences); + if (TextUtils.isEmpty(autoSubtypeLabel)) { + autoSelectionPref.setTitle( + R.string.use_system_language_to_select_input_method_subtypes); + } else { + autoSelectionPref.setTitle(autoSubtypeLabel); + } + } + + private boolean isNoSubtypesExplicitlySelected(final String imiId) { + final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); + for (final Preference pref : subtypePrefs) { + if (pref instanceof TwoStatePreference && ((TwoStatePreference) pref).isChecked()) { + return false; + } + } + return true; + } + + private void setAutoSelectionSubtypesEnabled(final String imiId, + final boolean autoSelectionEnabled) { + final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); + if (autoSelectionPref == null) { + return; + } + autoSelectionPref.setChecked(autoSelectionEnabled); + final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); + for (final Preference pref : subtypePrefs) { + if (pref instanceof TwoStatePreference) { + // When autoSelectionEnabled is true, all subtype prefs need to be disabled with + // implicitly checked subtypes. In case of false, all subtype prefs need to be + // enabled. + pref.setEnabled(!autoSelectionEnabled); + if (autoSelectionEnabled) { + ((TwoStatePreference) pref).setChecked(false); + } + } + } + if (autoSelectionEnabled) { + InputMethodAndSubtypeUtilCompat.saveInputMethodSubtypeList( + mFragment, mFragment.getContext().getContentResolver(), + mInputMethodInfoList, mHaveHardKeyboard); + updateImplicitlyEnabledSubtypes(imiId); + } + } + + private void updateImplicitlyEnabledSubtypes(final String targetImiId) { + // When targetImiId is null, apply to all subtypes of all IMEs + for (final InputMethodInfo imi : mInputMethodInfoList) { + final String imiId = imi.getId(); + final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId); + // No need to update implicitly enabled subtypes when the user has unchecked the + // "subtype auto selection". + if (autoSelectionPref == null || !autoSelectionPref.isChecked()) { + continue; + } + if (imiId.equals(targetImiId) || targetImiId == null) { + updateImplicitlyEnabledSubtypesOf(imi); + } + } + } + + private void updateImplicitlyEnabledSubtypesOf(final InputMethodInfo imi) { + final String imiId = imi.getId(); + final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId); + final List<InputMethodSubtype> implicitlyEnabledSubtypes = + mImm.getEnabledInputMethodSubtypeList(imi, true); + if (subtypePrefs == null || implicitlyEnabledSubtypes == null) { + return; + } + for (final Preference pref : subtypePrefs) { + if (!(pref instanceof TwoStatePreference)) { + continue; + } + final TwoStatePreference subtypePref = (TwoStatePreference) pref; + subtypePref.setChecked(false); + for (final InputMethodSubtype subtype : implicitlyEnabledSubtypes) { + final String implicitlyEnabledSubtypePrefKey = imiId + subtype.hashCode(); + if (subtypePref.getKey().equals(implicitlyEnabledSubtypePrefKey)) { + subtypePref.setChecked(true); + break; + } + } + } + } + + private void updateAutoSelectionPreferences() { + for (final String imiId : mInputMethodAndSubtypePrefsMap.keySet()) { + setAutoSelectionSubtypesEnabled(imiId, isNoSubtypesExplicitlySelected(imiId)); + } + updateImplicitlyEnabledSubtypes(null /* targetImiId */ /* check */); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java new file mode 100644 index 000000000000..9ad2adbcc432 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.settingslib.inputmethod; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.icu.text.ListFormatter; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.text.TextUtils; +import android.util.Log; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.internal.app.LocaleHelper; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + +// TODO: Consolidate this with {@link InputMethodSettingValuesWrapper}. +public class InputMethodAndSubtypeUtilCompat { + + private static final boolean DEBUG = false; + private static final String TAG = "InputMethdAndSubtypeUtlCompat"; + + private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; + private static final char INPUT_METHOD_SEPARATER = ':'; + private static final char INPUT_METHOD_SUBTYPE_SEPARATER = ';'; + private static final int NOT_A_SUBTYPE_ID = -1; + + private static final TextUtils.SimpleStringSplitter sStringInputMethodSplitter + = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SEPARATER); + + private static final TextUtils.SimpleStringSplitter sStringInputMethodSubtypeSplitter + = new TextUtils.SimpleStringSplitter(INPUT_METHOD_SUBTYPE_SEPARATER); + + // InputMethods and subtypes are saved in the settings as follows: + // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1 + public static String buildInputMethodsAndSubtypesString( + final HashMap<String, HashSet<String>> imeToSubtypesMap) { + final StringBuilder builder = new StringBuilder(); + for (final String imi : imeToSubtypesMap.keySet()) { + if (builder.length() > 0) { + builder.append(INPUT_METHOD_SEPARATER); + } + final HashSet<String> subtypeIdSet = imeToSubtypesMap.get(imi); + builder.append(imi); + for (final String subtypeId : subtypeIdSet) { + builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId); + } + } + return builder.toString(); + } + + private static String buildInputMethodsString(final HashSet<String> imiList) { + final StringBuilder builder = new StringBuilder(); + for (final String imi : imiList) { + if (builder.length() > 0) { + builder.append(INPUT_METHOD_SEPARATER); + } + builder.append(imi); + } + return builder.toString(); + } + + private static int getInputMethodSubtypeSelected(ContentResolver resolver) { + try { + return Settings.Secure.getInt(resolver, + Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE); + } catch (SettingNotFoundException e) { + return NOT_A_SUBTYPE_ID; + } + } + + private static boolean isInputMethodSubtypeSelected(ContentResolver resolver) { + return getInputMethodSubtypeSelected(resolver) != NOT_A_SUBTYPE_ID; + } + + private static void putSelectedInputMethodSubtype(ContentResolver resolver, int hashCode) { + Settings.Secure.putInt(resolver, Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, hashCode); + } + + // Needs to modify InputMethodManageService if you want to change the format of saved string. + static HashMap<String, HashSet<String>> getEnabledInputMethodsAndSubtypeList( + ContentResolver resolver) { + final String enabledInputMethodsStr = Settings.Secure.getString( + resolver, Settings.Secure.ENABLED_INPUT_METHODS); + if (DEBUG) { + Log.d(TAG, "--- Load enabled input methods: " + enabledInputMethodsStr); + } + return parseInputMethodsAndSubtypesString(enabledInputMethodsStr); + } + + public static HashMap<String, HashSet<String>> parseInputMethodsAndSubtypesString( + final String inputMethodsAndSubtypesString) { + final HashMap<String, HashSet<String>> subtypesMap = new HashMap<>(); + if (TextUtils.isEmpty(inputMethodsAndSubtypesString)) { + return subtypesMap; + } + sStringInputMethodSplitter.setString(inputMethodsAndSubtypesString); + while (sStringInputMethodSplitter.hasNext()) { + final String nextImsStr = sStringInputMethodSplitter.next(); + sStringInputMethodSubtypeSplitter.setString(nextImsStr); + if (sStringInputMethodSubtypeSplitter.hasNext()) { + final HashSet<String> subtypeIdSet = new HashSet<>(); + // The first element is {@link InputMethodInfoId}. + final String imiId = sStringInputMethodSubtypeSplitter.next(); + while (sStringInputMethodSubtypeSplitter.hasNext()) { + subtypeIdSet.add(sStringInputMethodSubtypeSplitter.next()); + } + subtypesMap.put(imiId, subtypeIdSet); + } + } + return subtypesMap; + } + + private static HashSet<String> getDisabledSystemIMEs(ContentResolver resolver) { + HashSet<String> set = new HashSet<>(); + String disabledIMEsStr = Settings.Secure.getString( + resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS); + if (TextUtils.isEmpty(disabledIMEsStr)) { + return set; + } + sStringInputMethodSplitter.setString(disabledIMEsStr); + while(sStringInputMethodSplitter.hasNext()) { + set.add(sStringInputMethodSplitter.next()); + } + return set; + } + + public static void saveInputMethodSubtypeList(PreferenceFragmentCompat context, + ContentResolver resolver, List<InputMethodInfo> inputMethodInfos, + boolean hasHardKeyboard) { + String currentInputMethodId = Settings.Secure.getString(resolver, + Settings.Secure.DEFAULT_INPUT_METHOD); + final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver); + final HashMap<String, HashSet<String>> enabledIMEsAndSubtypesMap = + getEnabledInputMethodsAndSubtypeList(resolver); + final HashSet<String> disabledSystemIMEs = getDisabledSystemIMEs(resolver); + + boolean needsToResetSelectedSubtype = false; + for (final InputMethodInfo imi : inputMethodInfos) { + final String imiId = imi.getId(); + final Preference pref = context.findPreference(imiId); + if (pref == null) { + continue; + } + // In the choose input method screen or in the subtype enabler screen, + // <code>pref</code> is an instance of TwoStatePreference. + final boolean isImeChecked = (pref instanceof TwoStatePreference) ? + ((TwoStatePreference) pref).isChecked() + : enabledIMEsAndSubtypesMap.containsKey(imiId); + final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId); + final boolean systemIme = imi.isSystem(); + if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance( + context.getActivity()).isAlwaysCheckedIme(imi)) + || isImeChecked) { + if (!enabledIMEsAndSubtypesMap.containsKey(imiId)) { + // imiId has just been enabled + enabledIMEsAndSubtypesMap.put(imiId, new HashSet<>()); + } + final HashSet<String> subtypesSet = enabledIMEsAndSubtypesMap.get(imiId); + + boolean subtypePrefFound = false; + final int subtypeCount = imi.getSubtypeCount(); + for (int i = 0; i < subtypeCount; ++i) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + final String subtypeHashCodeStr = String.valueOf(subtype.hashCode()); + final TwoStatePreference subtypePref = (TwoStatePreference) context + .findPreference(imiId + subtypeHashCodeStr); + // In the Configure input method screen which does not have subtype preferences. + if (subtypePref == null) { + continue; + } + if (!subtypePrefFound) { + // Once subtype preference is found, subtypeSet needs to be cleared. + // Because of system change, hashCode value could have been changed. + subtypesSet.clear(); + // If selected subtype preference is disabled, needs to reset. + needsToResetSelectedSubtype = true; + subtypePrefFound = true; + } + // Checking <code>subtypePref.isEnabled()</code> is insufficient to determine + // whether the user manually enabled this subtype or not. Implicitly-enabled + // subtypes are also checked just as an indicator to users. We also need to + // check <code>subtypePref.isEnabled()</code> so that only manually enabled + // subtypes can be saved here. + if (subtypePref.isEnabled() && subtypePref.isChecked()) { + subtypesSet.add(subtypeHashCodeStr); + if (isCurrentInputMethod) { + if (selectedInputMethodSubtype == subtype.hashCode()) { + // Selected subtype is still enabled, there is no need to reset + // selected subtype. + needsToResetSelectedSubtype = false; + } + } + } else { + subtypesSet.remove(subtypeHashCodeStr); + } + } + } else { + enabledIMEsAndSubtypesMap.remove(imiId); + if (isCurrentInputMethod) { + // We are processing the current input method, but found that it's not enabled. + // This means that the current input method has been uninstalled. + // If currentInputMethod is already uninstalled, InputMethodManagerService will + // find the applicable IME from the history and the system locale. + if (DEBUG) { + Log.d(TAG, "Current IME was uninstalled or disabled."); + } + currentInputMethodId = null; + } + } + // If it's a disabled system ime, add it to the disabled list so that it + // doesn't get enabled automatically on any changes to the package list + if (systemIme && hasHardKeyboard) { + if (disabledSystemIMEs.contains(imiId)) { + if (isImeChecked) { + disabledSystemIMEs.remove(imiId); + } + } else { + if (!isImeChecked) { + disabledSystemIMEs.add(imiId); + } + } + } + } + + final String enabledIMEsAndSubtypesString = buildInputMethodsAndSubtypesString( + enabledIMEsAndSubtypesMap); + final String disabledSystemIMEsString = buildInputMethodsString(disabledSystemIMEs); + if (DEBUG) { + Log.d(TAG, "--- Save enabled inputmethod settings. :" + enabledIMEsAndSubtypesString); + Log.d(TAG, "--- Save disabled system inputmethod settings. :" + + disabledSystemIMEsString); + Log.d(TAG, "--- Save default inputmethod settings. :" + currentInputMethodId); + Log.d(TAG, "--- Needs to reset the selected subtype :" + needsToResetSelectedSubtype); + Log.d(TAG, "--- Subtype is selected :" + isInputMethodSubtypeSelected(resolver)); + } + + // Redefines SelectedSubtype when all subtypes are unchecked or there is no subtype + // selected. And if the selected subtype of the current input method was disabled, + // We should reset the selected input method's subtype. + if (needsToResetSelectedSubtype || !isInputMethodSubtypeSelected(resolver)) { + if (DEBUG) { + Log.d(TAG, "--- Reset inputmethod subtype because it's not defined."); + } + putSelectedInputMethodSubtype(resolver, NOT_A_SUBTYPE_ID); + } + + Settings.Secure.putString(resolver, + Settings.Secure.ENABLED_INPUT_METHODS, enabledIMEsAndSubtypesString); + if (disabledSystemIMEsString.length() > 0) { + Settings.Secure.putString(resolver, Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS, + disabledSystemIMEsString); + } + // If the current input method is unset, InputMethodManagerService will find the applicable + // IME from the history and the system locale. + Settings.Secure.putString(resolver, Settings.Secure.DEFAULT_INPUT_METHOD, + currentInputMethodId != null ? currentInputMethodId : ""); + } + + public static void loadInputMethodSubtypeList(final PreferenceFragmentCompat context, + final ContentResolver resolver, final List<InputMethodInfo> inputMethodInfos, + final Map<String, List<Preference>> inputMethodPrefsMap) { + final HashMap<String, HashSet<String>> enabledSubtypes = + getEnabledInputMethodsAndSubtypeList(resolver); + + for (final InputMethodInfo imi : inputMethodInfos) { + final String imiId = imi.getId(); + final Preference pref = context.findPreference(imiId); + if (pref instanceof TwoStatePreference) { + final TwoStatePreference subtypePref = (TwoStatePreference) pref; + final boolean isEnabled = enabledSubtypes.containsKey(imiId); + subtypePref.setChecked(isEnabled); + if (inputMethodPrefsMap != null) { + for (final Preference childPref: inputMethodPrefsMap.get(imiId)) { + childPref.setEnabled(isEnabled); + } + } + setSubtypesPreferenceEnabled(context, inputMethodInfos, imiId, isEnabled); + } + } + updateSubtypesPreferenceChecked(context, inputMethodInfos, enabledSubtypes); + } + + private static void setSubtypesPreferenceEnabled(final PreferenceFragmentCompat context, + final List<InputMethodInfo> inputMethodProperties, final String id, + final boolean enabled) { + final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); + for (final InputMethodInfo imi : inputMethodProperties) { + if (id.equals(imi.getId())) { + final int subtypeCount = imi.getSubtypeCount(); + for (int i = 0; i < subtypeCount; ++i) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + final TwoStatePreference pref = (TwoStatePreference) preferenceScreen + .findPreference(id + subtype.hashCode()); + if (pref != null) { + pref.setEnabled(enabled); + } + } + } + } + } + + private static void updateSubtypesPreferenceChecked(final PreferenceFragmentCompat context, + final List<InputMethodInfo> inputMethodProperties, + final HashMap<String, HashSet<String>> enabledSubtypes) { + final PreferenceScreen preferenceScreen = context.getPreferenceScreen(); + for (final InputMethodInfo imi : inputMethodProperties) { + final String id = imi.getId(); + if (!enabledSubtypes.containsKey(id)) { + // There is no need to enable/disable subtypes of disabled IMEs. + continue; + } + final HashSet<String> enabledSubtypesSet = enabledSubtypes.get(id); + final int subtypeCount = imi.getSubtypeCount(); + for (int i = 0; i < subtypeCount; ++i) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + final String hashCode = String.valueOf(subtype.hashCode()); + if (DEBUG) { + Log.d(TAG, "--- Set checked state: " + "id" + ", " + hashCode + ", " + + enabledSubtypesSet.contains(hashCode)); + } + final TwoStatePreference pref = (TwoStatePreference) preferenceScreen + .findPreference(id + hashCode); + if (pref != null) { + pref.setChecked(enabledSubtypesSet.contains(hashCode)); + } + } + } + } + + public static void removeUnnecessaryNonPersistentPreference(final Preference pref) { + final String key = pref.getKey(); + if (pref.isPersistent() || key == null) { + return; + } + final SharedPreferences prefs = pref.getSharedPreferences(); + if (prefs != null && prefs.contains(key)) { + prefs.edit().remove(key).apply(); + } + } + + @NonNull + public static String getSubtypeLocaleNameAsSentence(@Nullable InputMethodSubtype subtype, + @NonNull final Context context, @NonNull final InputMethodInfo inputMethodInfo) { + if (subtype == null) { + return ""; + } + final Locale locale = getDisplayLocale(context); + final CharSequence subtypeName = subtype.getDisplayName(context, + inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() + .applicationInfo); + return LocaleHelper.toSentenceCase(subtypeName.toString(), locale); + } + + @NonNull + public static String getSubtypeLocaleNameListAsSentence( + @NonNull final List<InputMethodSubtype> subtypes, @NonNull final Context context, + @NonNull final InputMethodInfo inputMethodInfo) { + if (subtypes.isEmpty()) { + return ""; + } + final Locale locale = getDisplayLocale(context); + final int subtypeCount = subtypes.size(); + final CharSequence[] subtypeNames = new CharSequence[subtypeCount]; + for (int i = 0; i < subtypeCount; i++) { + subtypeNames[i] = subtypes.get(i).getDisplayName(context, + inputMethodInfo.getPackageName(), inputMethodInfo.getServiceInfo() + .applicationInfo); + } + return LocaleHelper.toSentenceCase( + ListFormatter.getInstance(locale).format((Object[]) subtypeNames), locale); + } + + @NonNull + private static Locale getDisplayLocale(@Nullable final Context context) { + if (context == null) { + return Locale.getDefault(); + } + if (context.getResources() == null) { + return Locale.getDefault(); + } + final Configuration configuration = context.getResources().getConfiguration(); + if (configuration == null) { + return Locale.getDefault(); + } + final Locale configurationLocale = configuration.getLocales().get(0); + if (configurationLocale == null) { + return Locale.getDefault(); + } + return configurationLocale; + } + + public static boolean isValidSystemNonAuxAsciiCapableIme(InputMethodInfo imi) { + if (imi.isAuxiliaryIme() || !imi.isSystem()) { + return false; + } + final int subtypeCount = imi.getSubtypeCount(); + for (int i = 0; i < subtypeCount; ++i) { + final InputMethodSubtype subtype = imi.getSubtypeAt(i); + if (SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode()) + && subtype.isAsciiCapable()) { + return true; + } + } + return false; + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java new file mode 100644 index 000000000000..d7c14ad66baa --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.license; + +import android.content.Context; +import android.util.Log; + +import com.android.settingslib.utils.AsyncLoaderCompat; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import androidx.annotation.VisibleForTesting; + +/** + * LicenseHtmlLoader is a loader which loads a license html file from default license xml files. + */ +public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> { + private static final String TAG = "LicenseHtmlLoaderCompat"; + + private static final String[] DEFAULT_LICENSE_XML_PATHS = { + "/system/etc/NOTICE.xml.gz", + "/vendor/etc/NOTICE.xml.gz", + "/odm/etc/NOTICE.xml.gz", + "/oem/etc/NOTICE.xml.gz"}; + private static final String NOTICE_HTML_FILE_NAME = "NOTICE.html"; + + private Context mContext; + + public LicenseHtmlLoaderCompat(Context context) { + super(context); + mContext = context; + } + + @Override + public File loadInBackground() { + return generateHtmlFromDefaultXmlFiles(); + } + + @Override + protected void onDiscardResult(File f) { + } + + private File generateHtmlFromDefaultXmlFiles() { + final List<File> xmlFiles = getVaildXmlFiles(); + if (xmlFiles.isEmpty()) { + Log.e(TAG, "No notice file exists."); + return null; + } + + File cachedHtmlFile = getCachedHtmlFile(); + if (!isCachedHtmlFileOutdated(xmlFiles, cachedHtmlFile) + || generateHtmlFile(xmlFiles, cachedHtmlFile)) { + return cachedHtmlFile; + } + + return null; + } + + @VisibleForTesting + List<File> getVaildXmlFiles() { + final List<File> xmlFiles = new ArrayList(); + for (final String xmlPath : DEFAULT_LICENSE_XML_PATHS) { + File file = new File(xmlPath); + if (file.exists() && file.length() != 0) { + xmlFiles.add(file); + } + } + return xmlFiles; + } + + @VisibleForTesting + File getCachedHtmlFile() { + return new File(mContext.getCacheDir(), NOTICE_HTML_FILE_NAME); + } + + @VisibleForTesting + boolean isCachedHtmlFileOutdated(List<File> xmlFiles, File cachedHtmlFile) { + boolean outdated = true; + if (cachedHtmlFile.exists() && cachedHtmlFile.length() != 0) { + outdated = false; + for (File file : xmlFiles) { + if (cachedHtmlFile.lastModified() < file.lastModified()) { + outdated = true; + break; + } + } + } + return outdated; + } + + @VisibleForTesting + boolean generateHtmlFile(List<File> xmlFiles, File htmlFile) { + return LicenseHtmlGeneratorFromXml.generateHtml(xmlFiles, htmlFile); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java new file mode 100644 index 000000000000..3adbd4d01ca0 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.SET_FOREGROUND; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStatsHistory.FIELD_RX_BYTES; +import static android.net.NetworkStatsHistory.FIELD_TX_BYTES; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; + +import android.content.Context; +import android.net.INetworkStatsSession; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.os.Bundle; +import android.os.RemoteException; + +import com.android.settingslib.AppItem; + +import androidx.loader.content.AsyncTaskLoader; + +/** + * Loader for historical chart data for both network and UID details. + */ +public class ChartDataLoaderCompat extends AsyncTaskLoader<ChartData> { + private static final String KEY_TEMPLATE = "template"; + private static final String KEY_APP = "app"; + private static final String KEY_FIELDS = "fields"; + + private final INetworkStatsSession mSession; + private final Bundle mArgs; + + public static Bundle buildArgs(NetworkTemplate template, AppItem app) { + return buildArgs(template, app, FIELD_RX_BYTES | FIELD_TX_BYTES); + } + + public static Bundle buildArgs(NetworkTemplate template, AppItem app, int fields) { + final Bundle args = new Bundle(); + args.putParcelable(KEY_TEMPLATE, template); + args.putParcelable(KEY_APP, app); + args.putInt(KEY_FIELDS, fields); + return args; + } + + public ChartDataLoaderCompat(Context context, INetworkStatsSession session, Bundle args) { + super(context); + mSession = session; + mArgs = args; + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + forceLoad(); + } + + @Override + public ChartData loadInBackground() { + final NetworkTemplate template = mArgs.getParcelable(KEY_TEMPLATE); + final AppItem app = mArgs.getParcelable(KEY_APP); + final int fields = mArgs.getInt(KEY_FIELDS); + + try { + return loadInBackground(template, app, fields); + } catch (RemoteException e) { + // since we can't do much without history, and we don't want to + // leave with half-baked UI, we bail hard. + throw new RuntimeException("problem reading network stats", e); + } + } + + private ChartData loadInBackground(NetworkTemplate template, AppItem app, int fields) + throws RemoteException { + final ChartData data = new ChartData(); + data.network = mSession.getHistoryForNetwork(template, fields); + + if (app != null) { + // load stats for current uid and template + final int size = app.uids.size(); + for (int i = 0; i < size; i++) { + final int uid = app.uids.keyAt(i); + data.detailDefault = collectHistoryForUid( + template, uid, SET_DEFAULT, data.detailDefault); + data.detailForeground = collectHistoryForUid( + template, uid, SET_FOREGROUND, data.detailForeground); + } + + if (size > 0) { + data.detail = new NetworkStatsHistory(data.detailForeground.getBucketDuration()); + data.detail.recordEntireHistory(data.detailDefault); + data.detail.recordEntireHistory(data.detailForeground); + } else { + data.detailDefault = new NetworkStatsHistory(HOUR_IN_MILLIS); + data.detailForeground = new NetworkStatsHistory(HOUR_IN_MILLIS); + data.detail = new NetworkStatsHistory(HOUR_IN_MILLIS); + } + } + + return data; + } + + @Override + protected void onStopLoading() { + super.onStopLoading(); + cancelLoad(); + } + + @Override + protected void onReset() { + super.onReset(); + cancelLoad(); + } + + /** + * Collect {@link NetworkStatsHistory} for the requested UID, combining with + * an existing {@link NetworkStatsHistory} if provided. + */ + private NetworkStatsHistory collectHistoryForUid( + NetworkTemplate template, int uid, int set, NetworkStatsHistory existing) + throws RemoteException { + final NetworkStatsHistory history = mSession.getHistoryForUid( + template, uid, set, TAG_NONE, FIELD_RX_BYTES | FIELD_TX_BYTES); + + if (existing != null) { + existing.recordEntireHistory(history); + return existing; + } else { + return history; + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java new file mode 100644 index 000000000000..c311337d6cf5 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoaderCompat.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.net; + +import android.content.Context; +import android.net.INetworkStatsSession; +import android.net.NetworkStats; +import android.net.NetworkTemplate; +import android.os.Bundle; +import android.os.RemoteException; + +import androidx.loader.content.AsyncTaskLoader; + +public class SummaryForAllUidLoaderCompat extends AsyncTaskLoader<NetworkStats> { + private static final String KEY_TEMPLATE = "template"; + private static final String KEY_START = "start"; + private static final String KEY_END = "end"; + + private final INetworkStatsSession mSession; + private final Bundle mArgs; + + public static Bundle buildArgs(NetworkTemplate template, long start, long end) { + final Bundle args = new Bundle(); + args.putParcelable(KEY_TEMPLATE, template); + args.putLong(KEY_START, start); + args.putLong(KEY_END, end); + return args; + } + + public SummaryForAllUidLoaderCompat(Context context, INetworkStatsSession session, + Bundle args) { + super(context); + mSession = session; + mArgs = args; + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + forceLoad(); + } + + @Override + public NetworkStats loadInBackground() { + final NetworkTemplate template = mArgs.getParcelable(KEY_TEMPLATE); + final long start = mArgs.getLong(KEY_START); + final long end = mArgs.getLong(KEY_END); + + try { + return mSession.getSummaryForAllUid(template, start, end, false); + } catch (RemoteException e) { + return null; + } + } + + @Override + protected void onStopLoading() { + super.onStopLoading(); + cancelLoad(); + } + + @Override + protected void onReset() { + super.onReset(); + cancelLoad(); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java new file mode 100644 index 000000000000..179121739896 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.suggestions; + + +import android.content.ComponentName; +import android.content.Context; +import android.os.Bundle; +import android.service.settings.suggestions.Suggestion; +import android.util.Log; + +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.List; + +import androidx.annotation.Nullable; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; + +/** + * Manages IPC communication to SettingsIntelligence for suggestion related services. + */ +public class SuggestionControllerMixinCompat implements + SuggestionController.ServiceConnectionListener, androidx.lifecycle.LifecycleObserver, + LoaderManager.LoaderCallbacks<List<Suggestion>> { + + public interface SuggestionControllerHost { + /** + * Called when suggestion data fetching is ready. + */ + void onSuggestionReady(List<Suggestion> data); + + /** + * Returns {@link LoaderManager} associated with the host. If host is not attached to + * activity then return null. + */ + @Nullable + LoaderManager getLoaderManager(); + } + + private static final String TAG = "SuggestionCtrlMixin"; + private static final boolean DEBUG = false; + + private final Context mContext; + private final SuggestionController mSuggestionController; + private final SuggestionControllerHost mHost; + + private boolean mSuggestionLoaded; + + public SuggestionControllerMixinCompat(Context context, SuggestionControllerHost host, + Lifecycle lifecycle, ComponentName componentName) { + mContext = context.getApplicationContext(); + mHost = host; + mSuggestionController = new SuggestionController(mContext, componentName, + this /* serviceConnectionListener */); + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + if (DEBUG) { + Log.d(TAG, "SuggestionController started"); + } + mSuggestionController.start(); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + if (DEBUG) { + Log.d(TAG, "SuggestionController stopped."); + } + mSuggestionController.stop(); + } + + @Override + public void onServiceConnected() { + final LoaderManager loaderManager = mHost.getLoaderManager(); + if (loaderManager != null) { + loaderManager.restartLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS, + null /* args */, this /* callback */); + } + } + + @Override + public void onServiceDisconnected() { + if (DEBUG) { + Log.d(TAG, "SuggestionService disconnected"); + } + final LoaderManager loaderManager = mHost.getLoaderManager(); + if (loaderManager != null) { + loaderManager.destroyLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS); + } + } + + @Override + public Loader<List<Suggestion>> onCreateLoader(int id, Bundle args) { + if (id == SuggestionLoader.LOADER_ID_SUGGESTIONS) { + mSuggestionLoaded = false; + return new SuggestionLoaderCompat(mContext, mSuggestionController); + } + throw new IllegalArgumentException("This loader id is not supported " + id); + } + + @Override + public void onLoadFinished(Loader<List<Suggestion>> loader, List<Suggestion> data) { + mSuggestionLoaded = true; + mHost.onSuggestionReady(data); + } + + @Override + public void onLoaderReset(Loader<List<Suggestion>> loader) { + mSuggestionLoaded = false; + } + + public boolean isSuggestionLoaded() { + return mSuggestionLoaded; + } + + public void dismissSuggestion(Suggestion suggestion) { + mSuggestionController.dismissSuggestions(suggestion); + } + + public void launchSuggestion(Suggestion suggestion) { + mSuggestionController.launchSuggestion(suggestion); + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoaderCompat.java new file mode 100644 index 000000000000..066de19172de --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionLoaderCompat.java @@ -0,0 +1,54 @@ +/* + * 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.settingslib.suggestions; + +import android.content.Context; +import android.service.settings.suggestions.Suggestion; +import android.util.Log; + +import com.android.settingslib.utils.AsyncLoaderCompat; + +import java.util.List; + +public class SuggestionLoaderCompat extends AsyncLoaderCompat<List<Suggestion>> { + + public static final int LOADER_ID_SUGGESTIONS = 42; + private static final String TAG = "SuggestionLoader"; + + private final SuggestionController mSuggestionController; + + public SuggestionLoaderCompat(Context context, SuggestionController controller) { + super(context); + mSuggestionController = controller; + } + + @Override + protected void onDiscardResult(List<Suggestion> result) { + + } + + @Override + public List<Suggestion> loadInBackground() { + final List<Suggestion> data = mSuggestionController.getSuggestions(); + if (data == null) { + Log.d(TAG, "data is null"); + } else { + Log.d(TAG, "data size " + data.size()); + } + return data; + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoaderCompat.java new file mode 100644 index 000000000000..916d7e312631 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/utils/AsyncLoaderCompat.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.utils; + +import android.content.Context; + +import androidx.loader.content.AsyncTaskLoader; + +/** + * This class fills in some boilerplate for AsyncTaskLoader to actually load things. + * + * Subclasses need to implement {@link AsyncLoaderCompat#loadInBackground()} to perform the actual + * background task, and {@link AsyncLoaderCompat#onDiscardResult(T)} to clean up previously loaded + * results. + * + * This loader is based on the MailAsyncTaskLoader from the AOSP EmailUnified repo. + * + * @param <T> the data type to be loaded. + */ +public abstract class AsyncLoaderCompat<T> extends AsyncTaskLoader<T> { + private T mResult; + + public AsyncLoaderCompat(final Context context) { + super(context); + } + + @Override + protected void onStartLoading() { + if (mResult != null) { + deliverResult(mResult); + } + + if (takeContentChanged() || mResult == null) { + forceLoad(); + } + } + + @Override + protected void onStopLoading() { + cancelLoad(); + } + + @Override + public void deliverResult(final T data) { + if (isReset()) { + if (data != null) { + onDiscardResult(data); + } + return; + } + + final T oldResult = mResult; + mResult = data; + + if (isStarted()) { + super.deliverResult(data); + } + + if (oldResult != null && oldResult != mResult) { + onDiscardResult(oldResult); + } + } + + @Override + protected void onReset() { + super.onReset(); + + onStopLoading(); + + if (mResult != null) { + onDiscardResult(mResult); + } + mResult = null; + } + + @Override + public void onCanceled(final T data) { + super.onCanceled(data); + + if (data != null) { + onDiscardResult(data); + } + } + + /** + * Called when discarding the load results so subclasses can take care of clean-up or + * recycling tasks. This is not called if the same result (by way of pointer equality) is + * returned again by a subsequent call to loadInBackground, or if result is null. + * + * Note that this may be called concurrently with loadInBackground(), and in some circumstances + * may be called more than once for a given object. + * + * @param result The value returned from {@link AsyncLoaderCompat#loadInBackground()} which + * is to be discarded. + */ + protected abstract void onDiscardResult(T result); +} diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java new file mode 100644 index 000000000000..260ac838cb32 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.widget; + +import android.content.Context; + +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen; + +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + +public class FooterPreferenceMixinCompat implements LifecycleObserver, SetPreferenceScreen { + + private final PreferenceFragmentCompat mFragment; + private FooterPreference mFooterPreference; + + public FooterPreferenceMixinCompat(PreferenceFragmentCompat fragment, Lifecycle lifecycle) { + mFragment = fragment; + lifecycle.addObserver(this); + } + + @Override + public void setPreferenceScreen(PreferenceScreen preferenceScreen) { + if (mFooterPreference != null) { + preferenceScreen.addPreference(mFooterPreference); + } + } + + /** + * Creates a new {@link FooterPreference}. + */ + public FooterPreference createFooterPreference() { + final PreferenceScreen screen = mFragment.getPreferenceScreen(); + if (mFooterPreference != null && screen != null) { + screen.removePreference(mFooterPreference); + } + mFooterPreference = new FooterPreference(getPrefContext()); + + if (screen != null) { + screen.addPreference(mFooterPreference); + } + return mFooterPreference; + } + + /** + * Returns an UI context with theme properly set for new Preference objects. + */ + private Context getPrefContext() { + return mFragment.getPreferenceManager().getContext(); + } + + public boolean hasFooter() { + return mFooterPreference != null; + } +} + diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java new file mode 100644 index 000000000000..9ba996752f49 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/CustomEditTextPreferenceComaptTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.view.View; +import android.widget.EditText; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class CustomEditTextPreferenceComaptTest { + + @Mock + private View mView; + + private TestPreference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mPreference = new TestPreference(RuntimeEnvironment.application); + } + + @Test + public void bindDialogView_shouldRequestFocus() { + final String testText = ""; + final EditText editText = spy(new EditText(RuntimeEnvironment.application)); + editText.setText(testText); + when(mView.findViewById(android.R.id.edit)).thenReturn(editText); + + mPreference.onBindDialogView(mView); + + verify(editText).requestFocus(); + } + + @Test + public void getEditText_noDialog_shouldNotCrash() { + ReflectionHelpers.setField(mPreference, "mFragment", + mock(CustomEditTextPreferenceCompat.CustomPreferenceDialogFragment.class)); + + mPreference.getEditText(); + + // no crash + } + + private static class TestPreference extends CustomEditTextPreferenceCompat { + public TestPreference(Context context) { + super(context); + } + } +} 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 a23eebcce797..23087a971611 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 @@ -21,8 +21,10 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -51,7 +53,8 @@ public class PowerWhitelistBackendTest { @Mock private IDeviceIdleController mDeviceIdleService; - + @Mock + private DevicePolicyManager mDevicePolicyManager; private PowerWhitelistBackend mPowerWhitelistBackend; private ShadowPackageManager mPackageManager; private Context mContext; @@ -59,7 +62,8 @@ public class PowerWhitelistBackendTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); + doReturn(mContext).when(mContext).getApplicationContext(); doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist(); doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle(); @@ -67,6 +71,7 @@ public class PowerWhitelistBackendTest { doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString()); mPackageManager = Shadow.extract(mContext.getPackageManager()); mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true); + doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class); mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService); } @@ -123,6 +128,13 @@ public class PowerWhitelistBackendTest { } @Test + public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() { + doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE); + + assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); + } + + @Test public void testIsSystemWhitelisted() throws Exception { doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist(); mPowerWhitelistBackend.refreshList(); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java new file mode 100644 index 000000000000..ddadac105c18 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.inputmethod; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.pm.ApplicationInfo; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodSubtype; +import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +@RunWith(RobolectricTestRunner.class) +public class InputMethodAndSubtypeUtilCompatTest { + + private static final HashSet<String> EMPTY_STRING_SET = new HashSet<>(); + + private static HashSet<String> asHashSet(String... strings) { + HashSet<String> hashSet = new HashSet<>(); + for (String s : strings) { + hashSet.add(s); + } + return hashSet; + } + + @Test + public void parseInputMethodsAndSubtypesString_EmptyString() { + assertThat(InputMethodAndSubtypeUtilCompat. + parseInputMethodsAndSubtypesString("")).isEmpty(); + assertThat(InputMethodAndSubtypeUtilCompat. + parseInputMethodsAndSubtypesString(null)).isEmpty(); + } + + @Test + public void parseInputMethodsAndSubtypesString_SingleImeNoSubtype() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString("ime0"); + assertThat(r).containsExactly("ime0", EMPTY_STRING_SET); + } + + @Test + public void parseInputMethodsAndSubtypesString_MultipleImesNoSubtype() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString("ime0:ime1"); + assertThat(r).containsExactly("ime0", EMPTY_STRING_SET, "ime1", EMPTY_STRING_SET); + } + + @Test + public void parseInputMethodsAndSubtypesString_SingleImeSingleSubtype() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString("ime0;subtype0"); + assertThat(r).containsExactly("ime0", asHashSet("subtype0")); + } + + @Test + public void parseInputMethodsAndSubtypesString_SingleImeDuplicateSameSubtypes() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype0"); + assertThat(r).containsExactly("ime0", asHashSet("subtype0")); + } + + @Test + public void parseInputMethodsAndSubtypesString_SingleImeMultipleSubtypes() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1"); + assertThat(r).containsExactly("ime0", asHashSet("subtype0", "subtype1")); + } + + @Test + public void parseInputMethodsAndSubtypesString_MultiplePairsOfImeSubtype() { + assertThat(InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0:ime1;subtype1")) + .containsExactly("ime0", asHashSet("subtype0"), "ime1", asHashSet("subtype1")); + assertThat(InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype2")) + .containsExactly("ime0", asHashSet("subtype0", "subtype1"), + "ime1", asHashSet("subtype2")); + assertThat(InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype1;subtype2")) + .containsExactly("ime0", asHashSet("subtype0", "subtype1"), + "ime1", asHashSet("subtype1", "subtype2")); + + } + + @Test + public void parseInputMethodsAndSubtypesString_MixedImeSubtypePairsAndImeNoSubtype() { + HashMap<String, HashSet<String>> r = + InputMethodAndSubtypeUtilCompat.parseInputMethodsAndSubtypesString( + "ime0;subtype0;subtype1:ime1;subtype1;subtype2:ime2"); + assertThat(r).containsExactly("ime0", asHashSet("subtype0", "subtype1"), + "ime1", asHashSet("subtype1", "subtype2"), + "ime2", EMPTY_STRING_SET); + } + + @Test + public void buildInputMethodsAndSubtypesString_EmptyInput() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + assertThat(map).isEmpty(); + } + + @Test + public void buildInputMethodsAndSubtypesString_SingleIme() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", new HashSet<>()); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + assertThat(result).isEqualTo("ime0"); + } + + @Test + public void buildInputMethodsAndSubtypesString_SingleImeSingleSubtype() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", asHashSet("subtype0")); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + assertThat(result).isEqualTo("ime0;subtype0"); + } + + @Test + public void buildInputMethodsAndSubtypesString_SingleImeMultipleSubtypes() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", asHashSet("subtype0", "subtype1")); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + + // We do not expect what order will be used to concatenate items in + // InputMethodAndSubtypeUtil.buildInputMethodsAndSubtypesString() hence accept all possible + // permutations here. + assertThat(result).matches("ime0;subtype0;subtype1|ime0;subtype1;subtype0"); + } + + @Test + public void buildInputMethodsAndSubtypesString_MultipleImesNoSubtypes() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", EMPTY_STRING_SET); + map.put("ime1", EMPTY_STRING_SET); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + + // We do not expect what order will be used to concatenate items in + // InputMethodAndSubtypeUtil.buildInputMethodsAndSubtypesString() hence accept all possible + // permutations here. + assertThat(result).matches("ime0:ime1|ime1:ime0"); + } + + @Test + public void buildInputMethodsAndSubtypesString_MultipleImesWithAndWithoutSubtypes() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", asHashSet("subtype0", "subtype1")); + map.put("ime1", EMPTY_STRING_SET); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + + // We do not expect what order will be used to concatenate items in + // InputMethodAndSubtypeUtil.buildInputMethodsAndSubtypesString() hence accept all possible + // permutations here. + assertThat(result).matches("ime0;subtype0;subtype1:ime1|ime0;subtype1;subtype0:ime1" + + "|ime1:ime0;subtype0;subtype1|ime1:ime0;subtype1;subtype0"); + } + + @Test + public void buildInputMethodsAndSubtypesString_MultipleImesWithSubtypes() { + HashMap<String, HashSet<String>> map = new HashMap<>(); + map.put("ime0", asHashSet("subtype0", "subtype1")); + map.put("ime1", asHashSet("subtype2", "subtype3")); + String result = InputMethodAndSubtypeUtilCompat.buildInputMethodsAndSubtypesString(map); + + // We do not expect what order will be used to concatenate items in + // InputMethodAndSubtypeUtil.buildInputMethodsAndSubtypesString() hence accept all possible + // permutations here. + assertThat(result).matches("ime0;subtype0;subtype1:ime1;subtype2;subtype3" + + "|ime0;subtype1;subtype0:ime1;subtype2;subtype3" + + "|ime0;subtype0;subtype1:ime1;subtype3;subtype2" + + "|ime0;subtype1;subtype0:ime1;subtype3;subtype2" + + "|ime1;subtype2;subtype3:ime0;subtype0;subtype1" + + "|ime2;subtype3;subtype2:ime0;subtype0;subtype1" + + "|ime3;subtype2;subtype3:ime0;subtype1;subtype0" + + "|ime4;subtype3;subtype2:ime0;subtype1;subtype0"); + } + + @Test + public void isValidSystemNonAuxAsciiCapableIme() { + // System IME w/ no subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, false))) + .isFalse(); + + // System IME w/ non-Aux and non-ASCII-capable "keyboard" subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, false, createDummySubtype("keyboard", false, false)))) + .isFalse(); + + // System IME w/ non-Aux and ASCII-capable "keyboard" subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, false, createDummySubtype("keyboard", false, true)))) + .isTrue(); + + // System IME w/ Aux and ASCII-capable "keyboard" subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, true, createDummySubtype("keyboard", true, true)))) + .isFalse(); + + // System IME w/ non-Aux and ASCII-capable "voice" subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, false, createDummySubtype("voice", false, true)))) + .isFalse(); + + // System IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(true, false, + createDummySubtype("keyboard", false, true), + createDummySubtype("keyboard", false, false)))) + .isTrue(); + + // Non-system IME w/ non-Aux and ASCII-capable "keyboard" subtype + assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( + createDummyIme(false, false, createDummySubtype("keyboard", false, true)))) + .isFalse(); + } + + private static InputMethodInfo createDummyIme(boolean isSystem, boolean isAuxIme, + InputMethodSubtype... subtypes) { + final ResolveInfo ri = new ResolveInfo(); + final ServiceInfo si = new ServiceInfo(); + final ApplicationInfo ai = new ApplicationInfo(); + ai.packageName = "com.example.android.dummyime"; + ai.enabled = true; + ai.flags |= (isSystem ? ApplicationInfo.FLAG_SYSTEM : 0); + si.applicationInfo = ai; + si.enabled = true; + si.packageName = "com.example.android.dummyime"; + si.name = "Dummy IME"; + si.exported = true; + si.nonLocalizedLabel = "Dummy IME"; + ri.serviceInfo = si; + return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false); + } + + private static InputMethodSubtype createDummySubtype( + String mode, boolean isAuxiliary, boolean isAsciiCapable) { + return new InputMethodSubtypeBuilder() + .setSubtypeNameResId(0) + .setSubtypeIconResId(0) + .setSubtypeLocale("en_US") + .setLanguageTag("en-US") + .setSubtypeMode(mode) + .setIsAuxiliary(isAuxiliary) + .setIsAsciiCapable(isAsciiCapable) + .build(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java new file mode 100644 index 000000000000..f981f365ec2b --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlLoaderCompatTest.java @@ -0,0 +1,108 @@ +/* + * 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.settingslib.license; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.util.ArrayList; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class LicenseHtmlLoaderCompatTest { + @Mock + private Context mContext; + + LicenseHtmlLoaderCompat newLicenseHtmlLoader(ArrayList<File> xmlFiles, + File cachedHtmlFile, boolean isCachedHtmlFileOutdated, + boolean generateHtmlFileSucceeded) { + LicenseHtmlLoaderCompat loader = spy(new LicenseHtmlLoaderCompat(mContext)); + doReturn(xmlFiles).when(loader).getVaildXmlFiles(); + doReturn(cachedHtmlFile).when(loader).getCachedHtmlFile(); + doReturn(isCachedHtmlFileOutdated).when(loader).isCachedHtmlFileOutdated(any(), any()); + doReturn(generateHtmlFileSucceeded).when(loader).generateHtmlFile(any(), any()); + return loader; + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testLoadInBackground() { + ArrayList<File> xmlFiles = new ArrayList(); + xmlFiles.add(new File("test.xml")); + File cachedHtmlFile = new File("test.html"); + + LicenseHtmlLoaderCompat loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, true); + + assertThat(loader.loadInBackground()).isEqualTo(cachedHtmlFile); + verify(loader).generateHtmlFile(any(), any()); + } + + @Test + public void testLoadInBackgroundWithNoVaildXmlFiles() { + ArrayList<File> xmlFiles = new ArrayList(); + File cachedHtmlFile = new File("test.html"); + + LicenseHtmlLoaderCompat loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, true); + + assertThat(loader.loadInBackground()).isNull(); + verify(loader, never()).generateHtmlFile(any(), any()); + } + + @Test + public void testLoadInBackgroundWithNonOutdatedCachedHtmlFile() { + ArrayList<File> xmlFiles = new ArrayList(); + xmlFiles.add(new File("test.xml")); + File cachedHtmlFile = new File("test.html"); + + LicenseHtmlLoaderCompat loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, false, + true); + + assertThat(loader.loadInBackground()).isEqualTo(cachedHtmlFile); + verify(loader, never()).generateHtmlFile(any(), any()); + } + + @Test + public void testLoadInBackgroundWithGenerateHtmlFileFailed() { + ArrayList<File> xmlFiles = new ArrayList(); + xmlFiles.add(new File("test.xml")); + File cachedHtmlFile = new File("test.html"); + + LicenseHtmlLoaderCompat loader = newLicenseHtmlLoader(xmlFiles, cachedHtmlFile, true, + false); + + assertThat(loader.loadInBackground()).isNull(); + verify(loader).generateHtmlFile(any(), any()); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java new file mode 100644 index 000000000000..1ee3afa9c1ce --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.suggestions; + +import static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.Context; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import androidx.lifecycle.LifecycleOwner; +import androidx.loader.app.LoaderManager; + +@RunWith(SettingsLibRobolectricTestRunner.class) +@Config(shadows = ShadowSuggestionController.class) +public class SuggestionControllerMixinCompatTest { + + @Mock + private SuggestionControllerMixinCompat.SuggestionControllerHost mHost; + + private Context mContext; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + private SuggestionControllerMixinCompat mMixin; + private ComponentName mComponentName; + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + mComponentName = new ComponentName( + "com.android.settings.intelligence", + "com.android.settings.intelligence.suggestions.SuggestionService"); + } + + @After + public void tearDown() { + ShadowSuggestionController.reset(); + } + + @Test + public void goThroughLifecycle_onStartStop_shouldStartStopController() { + mMixin = new SuggestionControllerMixinCompat(mContext, mHost, mLifecycle, mComponentName); + + mLifecycle.handleLifecycleEvent(ON_START); + assertThat(ShadowSuggestionController.sStartCalled).isTrue(); + + mLifecycle.handleLifecycleEvent(ON_STOP); + assertThat(ShadowSuggestionController.sStopCalled).isTrue(); + } + + @Test + public void onServiceConnected_shouldGetSuggestion() { + final LoaderManager loaderManager = mock(LoaderManager.class); + when(mHost.getLoaderManager()).thenReturn(loaderManager); + + mMixin = new SuggestionControllerMixinCompat(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceConnected(); + + verify(loaderManager).restartLoader(SuggestionLoader.LOADER_ID_SUGGESTIONS, + null /* args */, mMixin /* callback */); + } + + @Test + public void onServiceConnected_hostNotAttached_shouldDoNothing() { + when(mHost.getLoaderManager()).thenReturn(null); + + mMixin = new SuggestionControllerMixinCompat(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceConnected(); + + verify(mHost).getLoaderManager(); + } + + @Test + public void onServiceDisconnected_hostNotAttached_shouldDoNothing() { + when(mHost.getLoaderManager()).thenReturn(null); + + mMixin = new SuggestionControllerMixinCompat(mContext, mHost, mLifecycle, mComponentName); + mMixin.onServiceDisconnected(); + + verify(mHost).getLoaderManager(); + } + + @Test + public void doneLoadingg_shouldSetSuggestionLoaded() { + mMixin = new SuggestionControllerMixinCompat(mContext, mHost, mLifecycle, mComponentName); + + mMixin.onLoadFinished(mock(SuggestionLoaderCompat.class), null); + + assertThat(mMixin.isSuggestionLoaded()).isTrue(); + + mMixin.onLoaderReset(mock(SuggestionLoaderCompat.class)); + + assertThat(mMixin.isSuggestionLoaded()).isFalse(); + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java new file mode 100644 index 000000000000..1abbaba441ee --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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.settingslib.widget; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.shadows.ShadowApplication; + +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsLibRobolectricTestRunner.class) +public class FooterPreferenceMixinCompatTest { + + @Mock + private PreferenceFragmentCompat mFragment; + @Mock + private PreferenceScreen mScreen; + + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; + private FooterPreferenceMixinCompat mMixin; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); + when(mFragment.getPreferenceManager()).thenReturn(mock(PreferenceManager.class)); + when(mFragment.getPreferenceManager().getContext()) + .thenReturn(ShadowApplication.getInstance().getApplicationContext()); + mMixin = new FooterPreferenceMixinCompat(mFragment, mLifecycle); + } + + @Test + public void createFooter_screenNotAvailable_noCrash() { + assertThat(mMixin.createFooterPreference()).isNotNull(); + } + + @Test + public void createFooter_screenAvailable_canAttachToScreen() { + when(mFragment.getPreferenceScreen()).thenReturn(mScreen); + + final FooterPreference preference = mMixin.createFooterPreference(); + + assertThat(preference).isNotNull(); + verify(mScreen).addPreference(preference); + } + + @Test + public void createFooter_screenAvailableDelayed_canAttachToScreen() { + final FooterPreference preference = mMixin.createFooterPreference(); + + mLifecycle.setPreferenceScreen(mScreen); + + assertThat(preference).isNotNull(); + verify(mScreen).addPreference(preference); + } + + @Test + public void createFooterTwice_screenAvailable_replaceOldFooter() { + when(mFragment.getPreferenceScreen()).thenReturn(mScreen); + + mMixin.createFooterPreference(); + mMixin.createFooterPreference(); + + verify(mScreen).removePreference(any(FooterPreference.class)); + verify(mScreen, times(2)).addPreference(any(FooterPreference.class)); + } + +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java index 78b7616716f5..8604d186f2dd 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java @@ -23,11 +23,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.PreferenceFragment; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -38,6 +33,11 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.shadows.ShadowApplication; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + @RunWith(SettingsLibRobolectricTestRunner.class) public class FooterPreferenceMixinTest { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index eab4b9713b61..a5616d5e80ae 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -339,19 +339,17 @@ android:exported="false"> </activity> - <!-- Springboard for launching the share activity --> - <receiver android:name=".screenshot.GlobalScreenshot$ScreenshotActionReceiver" - android:process=":screenshot" + <!-- Springboard for launching the share and edit activity. This needs to be in the main + system ui process since we need to notify the status bar to dismiss the keyguard --> + <receiver android:name=".screenshot.GlobalScreenshot$ActionProxyReceiver" android:exported="false" /> <!-- Callback for dismissing screenshot notification after a share target is picked --> <receiver android:name=".screenshot.GlobalScreenshot$TargetChosenReceiver" - android:process=":screenshot" android:exported="false" /> <!-- Callback for deleting screenshot notification --> <receiver android:name=".screenshot.GlobalScreenshot$DeleteScreenshotReceiver" - android:process=":screenshot" android:exported="false" /> <!-- started from UsbDeviceSettingsManager --> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 6bc096534bb5..1d5aa6d76991 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -48,10 +48,10 @@ <string name="keyguard_enter_your_pin">Enter your PIN</string> <!-- Instructions telling the user to enter their pattern to unlock the keyguard [CHAR LIMIT=30] --> - <string name="keyguard_enter_your_pattern">Enter your Pattern</string> + <string name="keyguard_enter_your_pattern">Enter your pattern</string> <!-- Instructions telling the user to enter their text password to unlock the keyguard [CHAR LIMIT=30] --> - <string name="keyguard_enter_your_password">Enter your Password</string> + <string name="keyguard_enter_your_password">Enter your password</string> <!-- Instructions telling the user that they entered the wrong pin while trying to unlock the keyguard. Displayed in one line in a large font. --> @@ -62,7 +62,7 @@ <!-- When the lock screen is showing, the phone is plugged in and the battery is fully charged, say that it is charged. --> - <string name="keyguard_charged">Charged</string> + <string name="keyguard_charged">Fully charged</string> <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's charging. --> @@ -146,9 +146,9 @@ <!-- Message shown in pattern unlock after some number of unsuccessful attempts --> <string name="kg_forgot_pattern_button_text">Forgot Pattern</string> <!-- Message shown when user enters wrong pattern --> - <string name="kg_wrong_pattern">Wrong Pattern</string> + <string name="kg_wrong_pattern">Wrong pattern</string> <!-- Message shown when user enters wrong password --> - <string name="kg_wrong_password">Wrong Password</string> + <string name="kg_wrong_password">Wrong password</string> <!-- Message shown when user enters wrong PIN --> <string name="kg_wrong_pin">Wrong PIN</string> <!-- Countdown message shown after too many failed unlock attempts --> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/color/qs_detail_progress_track.xml b/packages/SystemUI/res/color-night/qs_detail_progress_track.xml index c56382e6047f..c56382e6047f 100644 --- a/packages/overlays/SysuiDarkThemeOverlay/res/color/qs_detail_progress_track.xml +++ b/packages/SystemUI/res/color-night/qs_detail_progress_track.xml diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 786edf2becd7..f62249a74cdb 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -922,14 +922,18 @@ <dimen name="global_actions_translate">9dp</dimen> - <!-- the maximum offset in either direction that elements are moved horizontally to prevent - burn-in on AOD --> + <!-- The maximum offset in either direction that elements are moved horizontally to prevent + burn-in on AOD. --> <dimen name="burn_in_prevention_offset_x">8dp</dimen> - <!-- the maximum offset in either direction that elements are moved vertically to prevent - burn-in on AOD --> + <!-- The maximum offset in either direction that elements are moved vertically to prevent + burn-in on AOD. --> <dimen name="burn_in_prevention_offset_y">50dp</dimen> + <!-- The maximum offset in either direction that the charging indication moves vertically + to prevent burn-in on AOD. --> + <dimen name="charging_indication_burn_in_prevention_offset_y">5dp</dimen> + <dimen name="corner_size">8dp</dimen> <dimen name="top_padding">0dp</dimen> <dimen name="bottom_padding">48dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 988a51665316..f8670485caf7 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -335,10 +335,7 @@ <item name="*android:errorColor">?android:attr/colorError</item> </style> - <!-- Overlay manager may replace this theme --> - <style name="qs_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" /> - - <style name="qs_theme" parent="qs_base"> + <style name="qs_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings"> <item name="lightIconTheme">@style/QSIconTheme</item> <item name="darkIconTheme">@style/QSIconTheme</item> <item name="android:windowIsFloating">true</item> @@ -501,7 +498,7 @@ parent="@*android:style/TextAppearance.Material.Notification.Info"> </style> - <style name="edit_theme" parent="qs_base"> + <style name="edit_theme" parent="qs_theme"> <item name="android:colorBackground">?android:attr/colorSecondary</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java index 01b42545a8cf..bbc8ecdcc066 100644 --- a/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java +++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java @@ -92,6 +92,11 @@ public class AutoReinflateContainer extends FrameLayout implements } @Override + public void onUiModeChanged() { + inflateLayout(); + } + + @Override public void onLocaleListChanged() { inflateLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index 7742c5503f28..198a4e6cedb8 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -28,6 +28,7 @@ import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.widget.LinearLayout; + import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.leak.RotationUtils; @@ -41,14 +42,15 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { private static final String EDGE_BLEED = "sysui_hwui_edge_bleed"; private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider"; private final int[] mTmp2 = new int[2]; - private View mChild; + private View mList; private View mSeparatedView; private int mOldHeight; private boolean mAnimating; private AnimatorSet mAnimation; private View mDivision; private boolean mHasOutsideTouch; - private HardwareBgDrawable mBackground; + private HardwareBgDrawable mListBackground; + private HardwareBgDrawable mSeparatedViewBackground; private Animator mAnimator; private boolean mCollapse; private boolean mHasSeparatedButton; @@ -90,17 +92,19 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(), ROUNDED_DIVIDER, 0) != 0; updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); - mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext()); - if (mChild != null) { - mChild.setBackground(mBackground); - mSeparatedView.setBackground(mBackground); + mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext()); + mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, + getContext()); + if (mList != null) { + mList.setBackground(mListBackground); + mSeparatedView.setBackground(mSeparatedViewBackground); requestLayout(); } } private void updateEdgeMargin(int edge) { - if (mChild != null) { - MarginLayoutParams params = (MarginLayoutParams) mChild.getLayoutParams(); + if (mList != null) { + MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams(); if (mRotation == ROTATION_LANDSCAPE) { params.topMargin = edge; } else if (mRotation == ROTATION_SEASCAPE) { @@ -108,7 +112,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } else { params.rightMargin = edge; } - mChild.setLayoutParams(params); + mList.setLayoutParams(params); } if (mSeparatedView != null) { @@ -131,15 +135,15 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (mChild == null) { + if (mList == null) { if (getChildCount() != 0) { - mChild = getChildAt(0); - mChild.setBackground(mBackground); + mList = getChildAt(0); + mList.setBackground(mListBackground); mSeparatedView = getChildAt(1); - mSeparatedView.setBackground(mBackground); + mSeparatedView.setBackground(mSeparatedViewBackground); updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); - mOldHeight = mChild.getMeasuredHeight(); - mChild.addOnLayoutChangeListener( + mOldHeight = mList.getMeasuredHeight(); + mList.addOnLayoutChangeListener( (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> updatePosition()); updateRotation(); @@ -147,7 +151,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { return; } } - int newHeight = mChild.getMeasuredHeight(); + int newHeight = mList.getMeasuredHeight(); if (newHeight != mOldHeight) { animateChild(mOldHeight, newHeight); } @@ -196,27 +200,29 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } } if (to != ROTATION_NONE) { - if (mChild instanceof LinearLayout) { + if (mList instanceof LinearLayout) { mRotatedBackground = true; - mBackground.setRotatedBackground(true); - LinearLayout linearLayout = (LinearLayout) mChild; + mListBackground.setRotatedBackground(true); + mSeparatedViewBackground.setRotatedBackground(true); + LinearLayout linearLayout = (LinearLayout) mList; if (mSwapOrientation) { linearLayout.setOrientation(LinearLayout.HORIZONTAL); setOrientation(LinearLayout.HORIZONTAL); } - swapDimens(mChild); + swapDimens(mList); swapDimens(mSeparatedView); } } else { - if (mChild instanceof LinearLayout) { + if (mList instanceof LinearLayout) { mRotatedBackground = false; - mBackground.setRotatedBackground(false); - LinearLayout linearLayout = (LinearLayout) mChild; + mListBackground.setRotatedBackground(false); + mSeparatedViewBackground.setRotatedBackground(false); + LinearLayout linearLayout = (LinearLayout) mList; if (mSwapOrientation) { linearLayout.setOrientation(LinearLayout.VERTICAL); setOrientation(LinearLayout.VERTICAL); } - swapDimens(mChild); + swapDimens(mList); swapDimens(mSeparatedView); } } @@ -224,12 +230,12 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { private void rotateRight() { rotateRight(this); - rotateRight(mChild); + rotateRight(mList); swapDimens(this); - LayoutParams p = (LayoutParams) mChild.getLayoutParams(); + LayoutParams p = (LayoutParams) mList.getLayoutParams(); p.gravity = rotateGravityRight(p.gravity); - mChild.setLayoutParams(p); + mList.setLayoutParams(p); LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams(); separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity); @@ -282,12 +288,12 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { private void rotateLeft() { rotateLeft(this); - rotateLeft(mChild); + rotateLeft(mList); swapDimens(this); - LayoutParams p = (LayoutParams) mChild.getLayoutParams(); + LayoutParams p = (LayoutParams) mList.getLayoutParams(); p.gravity = rotateGravityLeft(p.gravity); - mChild.setLayoutParams(p); + mList.setLayoutParams(p); LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams(); separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity); @@ -379,14 +385,14 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { mAnimating = false; } }); - int fromTop = mChild.getTop(); - int fromBottom = mChild.getBottom(); + int fromTop = mList.getTop(); + int fromBottom = mList.getBottom(); int toTop = fromTop - ((newHeight - oldHeight) / 2); int toBottom = fromBottom + ((newHeight - oldHeight) / 2); - ObjectAnimator top = ObjectAnimator.ofInt(mChild, "top", fromTop, toTop); - top.addUpdateListener(animation -> mBackground.invalidateSelf()); + ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop); + top.addUpdateListener(animation -> mListBackground.invalidateSelf()); mAnimation.playTogether(top, - ObjectAnimator.ofInt(mChild, "bottom", fromBottom, toBottom)); + ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom)); } public void setDivisionView(View v) { @@ -400,29 +406,30 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } private void updatePosition() { - if (mChild == null) return; + if (mList == null) return; // If got separated button, setRotatedBackground to false, // all items won't get white background. - mBackground.setRotatedBackground(mHasSeparatedButton); + mListBackground.setRotatedBackground(mHasSeparatedButton); + mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton); if (mDivision != null && mDivision.getVisibility() == VISIBLE) { int index = mRotatedBackground ? 0 : 1; mDivision.getLocationOnScreen(mTmp2); float trans = mRotatedBackground ? mDivision.getTranslationX() : mDivision.getTranslationY(); int viewTop = (int) (mTmp2[index] + trans); - mChild.getLocationOnScreen(mTmp2); + mList.getLocationOnScreen(mTmp2); viewTop -= mTmp2[index]; setCutPoint(viewTop); } else { - setCutPoint(mChild.getMeasuredHeight()); + setCutPoint(mList.getMeasuredHeight()); } } private void setCutPoint(int point) { - int curPoint = mBackground.getCutPoint(); + int curPoint = mListBackground.getCutPoint(); if (curPoint == point) return; if (getAlpha() == 0 || curPoint == 0) { - mBackground.setCutPoint(point); + mListBackground.setCutPoint(point); return; } if (mAnimator != null) { @@ -432,7 +439,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { mAnimator.cancel(); } mEndPoint = point; - mAnimator = ObjectAnimator.ofInt(mBackground, "cutPoint", curPoint, point); + mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point); if (mCollapse) { mAnimator.setStartDelay(300); mCollapse = false; @@ -470,14 +477,14 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> { - if (mHasOutsideTouch || (mChild == null)) { + if (mHasOutsideTouch || (mList == null)) { inoutInfo.setTouchableInsets( ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME); return; } inoutInfo.setTouchableInsets( ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT); - inoutInfo.contentInsets.set(mChild.getLeft(), mChild.getTop(), - 0, getBottom() - mChild.getBottom()); + inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(), + 0, getBottom() - mList.getBottom()); }; } diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index aeef49689517..eb704c863ebc 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -31,6 +31,13 @@ import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator; */ public class Interpolators { public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + + /** + * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator FAST_OUT_SLOW_IN_REVERSE = + new PathInterpolator(0.8f, 0f, 0.6f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); @@ -51,4 +58,11 @@ public class Interpolators { */ public static final Interpolator TOUCH_RESPONSE = new PathInterpolator(0.3f, 0f, 0.1f, 1f); + + /** + * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t + * goes from 1 to 0 instead of 0 to 1). + */ + public static final Interpolator TOUCH_RESPONSE_REVERSE = + new PathInterpolator(0.9f, 0f, 0.7f, 1f); } diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 1e5b77ee3aa4..d21465c53bdf 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -30,6 +30,7 @@ import android.os.Looper; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.UserHandle; +import android.provider.Settings; import android.util.Log; import android.view.SurfaceControl; @@ -99,7 +100,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis long token = Binder.clearCallingIdentity(); try { mHandler.post(() -> { - StatusBar statusBar = ((SystemUIApplication) mContext).getComponent( + StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class); if (statusBar != null) { statusBar.showScreenPinningRequest(taskId, false /* allowCancel */); @@ -152,7 +153,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis public Rect getNonMinimizedSplitScreenSecondaryBounds() { long token = Binder.clearCallingIdentity(); try { - Divider divider = ((SystemUIApplication) mContext).getComponent(Divider.class); + Divider divider = SysUiServiceProvider.getComponent(mContext, Divider.class); if (divider != null) { return divider.getView().getNonMinimizedSplitScreenSecondaryBounds(); } @@ -391,14 +392,22 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(TAG_OPS + " state:"); - pw.print(" mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts); + pw.print(" recentsComponentName="); pw.println(mRecentsComponentName); + pw.print(" isConnected="); pw.println(mOverviewProxy != null); pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController .isCurrentUserSetup()); - pw.print(" isConnected="); pw.println(mOverviewProxy != null); - pw.print(" mRecentsComponentName="); pw.println(mRecentsComponentName); - pw.print(" mIsEnabled="); pw.println(isEnabled()); - pw.print(" mInteractionFlags="); pw.println(mInteractionFlags); - pw.print(" mQuickStepIntent="); pw.println(mQuickStepIntent); + pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts); + pw.print(" interactionFlags="); pw.println(mInteractionFlags); + + pw.print(" quickStepIntent="); pw.println(mQuickStepIntent); + pw.print(" quickStepIntentResolved="); pw.println(isEnabled()); + + final int swipeUpDefaultValue = mContext.getResources() + .getBoolean(com.android.internal.R.bool.config_swipe_up_gesture_default) ? 1 : 0; + final int swipeUpEnabled = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SWIPE_UP_TO_SWITCH_APPS_ENABLED, swipeUpDefaultValue); + pw.print(" swipeUpSetting="); pw.println(swipeUpEnabled != 0); + pw.print(" swipeUpSettingDefault="); pw.println(swipeUpDefaultValue != 0); } public interface OverviewProxyListener { diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java index b7ff98402081..78632459c867 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java @@ -33,7 +33,6 @@ import com.android.systemui.util.AlarmTimeout; import com.android.systemui.util.wakelock.WakeLock; import java.util.Calendar; -import java.util.GregorianCalendar; /** * The policy controlling doze. @@ -113,9 +112,7 @@ public class DozeUi implements DozeMachine.Part { // The display buffers will be empty and need to be filled. mHost.dozeTimeTick(); // The first frame may arrive when the display isn't ready yet. - mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 100); - // The the delayed frame may arrive when the display isn't ready yet either. - mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 1000); + mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 500); } scheduleTimeTick(); break; @@ -184,7 +181,7 @@ public class DozeUi implements DozeMachine.Part { } private long roundToNextMinute(long timeInMillis) { - Calendar calendar = GregorianCalendar.getInstance(); + Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timeInMillis); calendar.set(Calendar.MILLISECOND, 0); calendar.set(Calendar.SECOND, 0); diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java index f422737bb9af..0ed1cd128caa 100644 --- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java +++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java @@ -51,7 +51,8 @@ public class FragmentHostManager { private final View mRootView; private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE - | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS); + | ActivityInfo.CONFIG_SCREEN_LAYOUT | ActivityInfo.CONFIG_ASSETS_PATHS + | ActivityInfo.CONFIG_UI_MODE); private final FragmentService mManager; private final ExtensionFragmentManager mPlugins = new ExtensionFragmentManager(); diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 532fa034a03b..201f40e40f26 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -265,7 +265,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, if (!mHasVibrator) { mSilentModeAction = new SilentModeToggleAction(); } else { - mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler); + mSilentModeAction = new SilentModeTriStateAction(mAudioManager, mHandler); } mAirplaneModeOn = new ToggleAction( R.drawable.ic_lock_airplane_mode, @@ -1211,12 +1211,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final AudioManager mAudioManager; private final Handler mHandler; - private final Context mContext; - SilentModeTriStateAction(Context context, AudioManager audioManager, Handler handler) { + SilentModeTriStateAction(AudioManager audioManager, Handler handler) { mAudioManager = audioManager; mHandler = handler; - mContext = context; } private int ringerModeToIndex(int ringerMode) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index b9d1021f086d..8d7eb6c719ff 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -346,6 +346,11 @@ public class KeyguardViewMediator extends SystemUI { */ private WorkLockActivityController mWorkLockController; + /** + * @see #setPulsing(boolean) + */ + private boolean mPulsing; + private boolean mLockLater; private boolean mWakeAndUnlocking; @@ -1801,10 +1806,12 @@ public class KeyguardViewMediator extends SystemUI { int flags = 0; if (mStatusBarKeyguardViewManager.shouldDisableWindowAnimationsForUnlock() - || mWakeAndUnlocking) { - flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; + || (mWakeAndUnlocking && !mPulsing)) { + flags |= WindowManagerPolicyConstants + .KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS; } - if (mStatusBarKeyguardViewManager.isGoingToNotificationShade()) { + if (mStatusBarKeyguardViewManager.isGoingToNotificationShade() + || (mWakeAndUnlocking && mPulsing)) { flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE; } if (mStatusBarKeyguardViewManager.isUnlockWithWallpaper()) { @@ -2103,10 +2110,20 @@ public class KeyguardViewMediator extends SystemUI { pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback); } + /** + * @param aodShowing true when AOD - or ambient mode - is showing. + */ public void setAodShowing(boolean aodShowing) { setShowingLocked(mShowing, aodShowing); } + /** + * @param pulsing true when device temporarily wakes up to display an incoming notification. + */ + public void setPulsing(boolean pulsing) { + mPulsing = pulsing; + } + private static class StartKeyguardExitAnimParams { long startTime; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index d9f923f2b4e3..020c5500c0a0 100644..100755 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -262,12 +262,13 @@ public class PipManager implements BasePipManager { entry = Pair.<String, String>create(packageAndClassName[0], null); break; case 2: - if (packageAndClassName[1] != null - && packageAndClassName[1].startsWith(".")) { - entry = Pair.<String, String>create( - packageAndClassName[0], - packageAndClassName[0] + packageAndClassName[1]); + if (packageAndClassName[1] != null) { + entry = Pair.<String, String>create(packageAndClassName[0], + packageAndClassName[1].startsWith(".") + ? packageAndClassName[0] + packageAndClassName[1] + : packageAndClassName[1]); } + break; } if (entry != null) { sSettingsPackageAndClassNamePairList.add(entry); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index e0a9148b1230..c41f087aa76b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -26,7 +26,6 @@ import android.provider.Settings; import android.service.quicksettings.Tile; import androidx.annotation.StringRes; import android.text.TextUtils; -import android.text.format.DateFormat; import android.util.Log; import android.widget.Switch; @@ -37,8 +36,11 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.plugins.qs.QSTile.BooleanState; import com.android.systemui.qs.tileimpl.QSTileImpl; +import java.text.DateFormat; import java.time.LocalTime; import java.time.format.DateTimeFormatter; +import java.util.Calendar; +import java.util.TimeZone; public class NightDisplayTile extends QSTileImpl<BooleanState> implements ColorDisplayController.Callback { @@ -144,13 +146,17 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> toggleTimeStringRes = R.string.quick_settings_night_secondary_label_on_at; } - // Choose between just showing the hour or also showing the minutes (based on the - // user-selected toggle time). This helps reduce how much space the label takes. - toggleTimeFormat = DateTimeFormatter.ofPattern( - DateFormat.is24HourFormat(mContext) ? PATTERN_HOUR_NINUTE_24 : - toggleTime.getMinute() == 0 ? PATTERN_HOUR : PATTERN_HOUR_MINUTE); - - return mContext.getString(toggleTimeStringRes, toggleTime.format(toggleTimeFormat)); + // TODO(b/111085930): Move this calendar snippet to a common code location that + // settings lib can also access. + final Calendar c = Calendar.getInstance(); + DateFormat nightTileFormat = android.text.format.DateFormat.getTimeFormat(mContext); + nightTileFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + c.setTimeZone(nightTileFormat.getTimeZone()); + c.set(Calendar.HOUR_OF_DAY, toggleTime.getHour()); + c.set(Calendar.MINUTE, toggleTime.getMinute()); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + return mContext.getString(toggleTimeStringRes, nightTileFormat.format(c.getTime())); default: // No secondary label when auto mode is disabled. diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 7e4acc2d0e28..63a65d030f6d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -48,6 +48,7 @@ import android.widget.Toast; import com.android.systemui.Dependency; import com.android.systemui.OverviewProxyService; +import com.android.systemui.SysUiServiceProvider; import com.google.android.collect.Lists; import com.android.internal.logging.MetricsLogger; @@ -1095,7 +1096,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } private StatusBar getStatusBar() { - return ((SystemUIApplication) mContext).getComponent(StatusBar.class); + return SysUiServiceProvider.getComponent(mContext, StatusBar.class); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java index 2c1158df3793..b4212d310fc0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUserService.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.os.IBinder; import android.util.Log; +import com.android.systemui.SysUiServiceProvider; import com.android.systemui.SystemUIApplication; /** @@ -40,8 +41,7 @@ public class RecentsSystemUserService extends Service { @Override public IBinder onBind(Intent intent) { - SystemUIApplication app = (SystemUIApplication) getApplication(); - Recents recents = app.getComponent(Recents.class); + Recents recents = SysUiServiceProvider.getComponent(this, Recents.class); if (DEBUG) { Log.d(TAG, "onBind: " + recents); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 64ccba810ff3..0ea941ff4f3e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -16,9 +16,11 @@ package com.android.systemui.screenshot; +import static android.content.Context.NOTIFICATION_SERVICE; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - -import static com.android.systemui.screenshot.GlobalScreenshot.SHARING_INTENT; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_ACTION_INTENT; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION; +import static com.android.systemui.screenshot.GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP; import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_SCREENSHOT; import android.animation.Animator; @@ -26,7 +28,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; -import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.Notification; import android.app.Notification.BigPictureStyle; @@ -56,9 +57,9 @@ import android.os.AsyncTask; import android.os.Environment; import android.os.PowerManager; import android.os.Process; -import android.os.RemoteException; import android.os.UserHandle; import android.provider.MediaStore; +import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; import android.util.Slog; @@ -73,12 +74,13 @@ import android.view.WindowManager; import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.Toast; - import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider; import com.android.systemui.SystemUI; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.util.NotificationChannels; - import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; @@ -277,7 +279,12 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { values.put(MediaStore.Images.ImageColumns.SIZE, new File(mImageFilePath).length()); Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); - // Create a share intent + // Note: Both the share and edit actions are proxied through ActionProxyReceiver in + // order to do some common work like dismissing the keyguard and sending + // closeSystemWindows + + // Create a share intent, this will always go through the chooser activity first which + // should not trigger auto-enter PiP String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime)); String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate); Intent sharingIntent = new Intent(Intent.ACTION_SEND); @@ -286,37 +293,47 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject); sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - // Create a share action for the notification. Note, we proxy the call to - // ScreenshotActionReceiver because RemoteViews currently forces an activity options - // on the PendingIntent being launched, and since we don't want to trigger the share - // sheet in this case, we start the chooser activity directly in - // ScreenshotActionReceiver. + PendingIntent chooserAction = PendingIntent.getBroadcast(context, 0, + new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, + chooserAction.getIntentSender()) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + + // Create a share action for the notification PendingIntent shareAction = PendingIntent.getBroadcast(context, 0, - new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class) - .putExtra(SHARING_INTENT, sharingIntent), + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent) + .putExtra(EXTRA_DISALLOW_ENTER_PIP, true), PendingIntent.FLAG_CANCEL_CURRENT); Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( R.drawable.ic_screenshot_share, r.getString(com.android.internal.R.string.share), shareAction); mNotificationBuilder.addAction(shareActionBuilder.build()); + // Create an edit intent, if a specific package is provided as the editor, then launch + // that directly + String editorPackage = context.getString(R.string.config_screenshotEditor); Intent editIntent = new Intent(Intent.ACTION_EDIT); + if (!TextUtils.isEmpty(editorPackage)) { + editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); + } editIntent.setType("image/png"); editIntent.setData(uri); editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - // Create a edit action for the notification the same way. + // Create a edit action PendingIntent editAction = PendingIntent.getBroadcast(context, 1, - new Intent(context, GlobalScreenshot.ScreenshotActionReceiver.class) - .putExtra(SHARING_INTENT, editIntent), + new Intent(context, GlobalScreenshot.ActionProxyReceiver.class) + .putExtra(EXTRA_ACTION_INTENT, editIntent) + .putExtra(EXTRA_CANCEL_NOTIFICATION, editIntent.getComponent() != null), PendingIntent.FLAG_CANCEL_CURRENT); Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( R.drawable.ic_screenshot_edit, r.getString(com.android.internal.R.string.screenshot_edit), editAction); mNotificationBuilder.addAction(editActionBuilder.build()); - // Create a delete action for the notification PendingIntent deleteAction = PendingIntent.getBroadcast(context, 0, new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class) @@ -429,7 +446,9 @@ class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> { class GlobalScreenshot { static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id"; - static final String SHARING_INTENT = "android:screenshot_sharing_intent"; + static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent"; + static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification"; + static final String EXTRA_DISALLOW_ENTER_PIP = "android:screenshot_disallow_enter_pip"; private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130; private static final int SCREENSHOT_DROP_IN_DURATION = 430; @@ -452,7 +471,6 @@ class GlobalScreenshot { private NotificationManager mNotificationManager; private Display mDisplay; private DisplayMetrics mDisplayMetrics; - private Matrix mDisplayMatrix; private Bitmap mScreenBitmap; private View mScreenshotLayout; @@ -482,7 +500,6 @@ class GlobalScreenshot { context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); // Inflate the screenshot layout - mDisplayMatrix = new Matrix(); mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background); mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot); @@ -512,7 +529,7 @@ class GlobalScreenshot { mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mNotificationManager = - (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); mDisplay = mWindowManager.getDefaultDisplay(); mDisplayMetrics = new DisplayMetrics(); mDisplay.getRealMetrics(mDisplayMetrics); @@ -562,21 +579,6 @@ class GlobalScreenshot { } /** - * @return the current display rotation in degrees - */ - private float getDegreesForRotation(int value) { - switch (value) { - case Surface.ROTATION_90: - return 360f - 90f; - case Surface.ROTATION_180: - return 360f - 180f; - case Surface.ROTATION_270: - return 360f - 270f; - } - return 0f; - } - - /** * Takes a screenshot of the current display and shows an animation. */ private void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible, @@ -891,52 +893,39 @@ class GlobalScreenshot { } /** - * Receiver to proxy the share or edit intent. + * Receiver to proxy the share or edit intent, used to clean up the notification and send + * appropriate signals to the system (ie. to dismiss the keyguard if necessary). */ - public static class ScreenshotActionReceiver extends BroadcastReceiver { + public static class ActionProxyReceiver extends BroadcastReceiver { @Override - public void onReceive(Context context, Intent intent) { - try { - ActivityManager.getService().closeSystemDialogs(SYSTEM_DIALOG_REASON_SCREENSHOT); - } catch (RemoteException e) { - } - - Intent actionIntent = intent.getParcelableExtra(SHARING_INTENT); - - // If this is an edit & default editor exists, route straight there. - String editorPackage = context.getResources().getString(R.string.config_screenshotEditor); - if (actionIntent.getAction() == Intent.ACTION_EDIT && - editorPackage != null && editorPackage.length() > 0) { - actionIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); - final NotificationManager nm = - (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); - } else { - PendingIntent chooseAction = PendingIntent.getBroadcast(context, 0, - new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); - actionIntent = Intent.createChooser(actionIntent, null, - chooseAction.getIntentSender()) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); - } - - ActivityOptions opts = ActivityOptions.makeBasic(); - opts.setDisallowEnterPictureInPictureWhileLaunching(true); - - context.startActivityAsUser(actionIntent, opts.toBundle(), UserHandle.CURRENT); + public void onReceive(Context context, final Intent intent) { + Runnable startActivityRunnable = () -> { + ActivityManagerWrapper.getInstance().closeSystemWindows( + SYSTEM_DIALOG_REASON_SCREENSHOT); + + Intent actionIntent = intent.getParcelableExtra(EXTRA_ACTION_INTENT); + if (intent.getBooleanExtra(EXTRA_CANCEL_NOTIFICATION, false)) { + cancelScreenshotNotification(context); + } + ActivityOptions opts = ActivityOptions.makeBasic(); + opts.setDisallowEnterPictureInPictureWhileLaunching( + intent.getBooleanExtra(EXTRA_DISALLOW_ENTER_PIP, false)); + context.startActivityAsUser(actionIntent, opts.toBundle(),UserHandle.CURRENT); + }; + StatusBar statusBar = SysUiServiceProvider.getComponent(context, StatusBar.class); + statusBar.executeRunnableDismissingKeyguard(startActivityRunnable, null, + true /* dismissShade */, true /* afterKeyguardGone */, true /* deferred */); } } /** - * Removes the notification for a screenshot after a share or edit target is chosen. + * Removes the notification for a screenshot after a share target is chosen. */ public static class TargetChosenReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - // Clear the notification - final NotificationManager nm = - (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); + // Clear the notification only after the user has chosen a share action + cancelScreenshotNotification(context); } } @@ -950,14 +939,18 @@ class GlobalScreenshot { return; } - // Clear the notification - final NotificationManager nm = - (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); - nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); + // Clear the notification when the image is deleted + cancelScreenshotNotification(context); // And delete the image from the media store + final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID)); new DeleteImageInBackgroundTask(context).execute(uri); } } + + private static void cancelScreenshotNotification(Context context) { + final NotificationManager nm = + (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); + nm.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 294e2f4a5ab4..551e8a9dcb81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -364,22 +364,41 @@ public class KeyguardIndicationController { R.integer.wired_charging_keyguard_text_animation_duration_up); int animateDownDuration = mContext.getResources().getInteger( R.integer.wired_charging_keyguard_text_animation_duration_down); + textView.animate().cancel(); + float translation = textView.getTranslationY(); textView.animate() .translationYBy(yTranslation) .setInterpolator(Interpolators.LINEAR) .setDuration(animateUpDuration) .setListener(new AnimatorListenerAdapter() { + private boolean mCancelled; + @Override public void onAnimationStart(Animator animation) { textView.switchIndication(indication); } + + @Override + public void onAnimationCancel(Animator animation) { + textView.setTranslationY(translation); + mCancelled = true; + } + @Override public void onAnimationEnd(Animator animation) { + if (mCancelled) { + return; + } textView.animate() .setDuration(animateDownDuration) .setInterpolator(Interpolators.BOUNCE) - .translationYBy(-1 * yTranslation) - .setListener(null); + .translationY(translation) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + textView.setTranslationY(translation); + } + }); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index 0b6fd1300538..2087a165b215 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -216,15 +216,28 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { // until the clock and the notifications are faded out. mStatusBarWindowManager.setForceDozeBrightness(true); } - if (!wasDeviceInteractive) { - if (DEBUG_BIO_WAKELOCK) { - Log.i(TAG, "bio wakelock: Authenticated, waking up..."); + // During wake and unlock, we need to draw black before waking up to avoid abrupt + // brightness changes due to display state transitions. + boolean alwaysOnEnabled = DozeParameters.getInstance(mContext).getAlwaysOn(); + boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled; + Runnable wakeUp = ()-> { + if (!wasDeviceInteractive) { + if (DEBUG_BIO_WAKELOCK) { + Log.i(TAG, "bio wakelock: Authenticated, waking up..."); + } + mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:BIOMETRIC"); + } + if (delayWakeUp) { + mKeyguardViewMediator.onWakeAndUnlocking(); } - mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:BIOMETRIC"); + Trace.beginSection("release wake-and-unlock"); + releaseBiometricWakeLock(); + Trace.endSection(); + }; + + if (!delayWakeUp) { + wakeUp.run(); } - Trace.beginSection("release wake-and-unlock"); - releaseBiometricWakeLock(); - Trace.endSection(); switch (mMode) { case MODE_DISMISS_BOUNCER: Trace.beginSection("MODE_DISMISS"); @@ -257,7 +270,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback { mUpdateMonitor.awakenFromDream(); } mStatusBarWindowManager.setStatusBarFocusable(false); - mKeyguardViewMediator.onWakeAndUnlocking(); + if (delayWakeUp) { + mHandler.postDelayed(wakeUp, 50); + } else { + mKeyguardViewMediator.onWakeAndUnlocking(); + } if (mStatusBar.getNavigationBarView() != null) { mStatusBar.getNavigationBarView().setWakeAndUnlocking(true); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java index 6f538440647e..7ddca1756070 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java @@ -64,8 +64,9 @@ public class ConfigurationControllerImpl implements ConfigurationController, final float fontScale = newConfig.fontScale; final int density = newConfig.densityDpi; int uiMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK; + boolean uiModeChanged = uiMode != mUiMode; if (density != mDensity || fontScale != mFontScale - || (mInCarMode && uiMode != mUiMode)) { + || (mInCarMode && uiModeChanged)) { listeners.forEach(l -> { if (mListeners.contains(l)) { l.onDensityOrFontScaleChanged(); @@ -73,7 +74,6 @@ public class ConfigurationControllerImpl implements ConfigurationController, }); mDensity = density; mFontScale = fontScale; - mUiMode = uiMode; } final LocaleList localeList = newConfig.getLocales(); @@ -86,6 +86,15 @@ public class ConfigurationControllerImpl implements ConfigurationController, }); } + if (uiModeChanged) { + mUiMode = uiMode; + listeners.forEach(l -> { + if (mListeners.contains(l)) { + l.onUiModeChanged(); + } + }); + } + if ((mLastConfig.updateFrom(newConfig) & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { listeners.forEach(l -> { if (mListeners.contains(l)) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 25b97bb96373..d89bcdaffe3e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -174,6 +174,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private int mIndicationBottomMarginAmbient; private float mDarkAmount; private int mBurnInXOffset; + private int mBurnInYOffset; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -247,6 +248,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL R.dimen.keyguard_indication_margin_bottom); mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_margin_bottom_ambient); + mBurnInYOffset = getResources().getDimensionPixelSize( + R.dimen.charging_indication_burn_in_prevention_offset_y); updateCameraVisibility(); mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); mUnlockMethodCache.addListener(this); @@ -319,6 +322,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL R.dimen.keyguard_indication_margin_bottom); mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_margin_bottom_ambient); + mBurnInYOffset = getResources().getDimensionPixelSize( + R.dimen.charging_indication_burn_in_prevention_offset_y); MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams(); if (mlp.bottomMargin != mIndicationBottomMargin) { mlp.bottomMargin = mIndicationBottomMargin; @@ -562,12 +567,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL return; } mDarkAmount = darkAmount; - // Let's randomize the bottom margin every time we wake up to avoid burn-in. - if (darkAmount == 0) { - mIndicationBottomMarginAmbient = getResources().getDimensionPixelSize( - R.dimen.keyguard_indication_margin_bottom_ambient) - + (int) (Math.random() * mIndicationText.getTextSize()); - } mIndicationArea.setAlpha(MathUtils.lerp(1f, 0.7f, darkAmount)); mIndicationArea.setTranslationY(MathUtils.lerp(0, mIndicationBottomMargin - mIndicationBottomMarginAmbient, darkAmount)); @@ -844,8 +843,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void dozeTimeTick() { if (mDarkAmount == 1) { // Move indication every minute to avoid burn-in - final int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient; - mIndicationArea.setTranslationY(dozeTranslation + (float) Math.random() * 5); + int dozeTranslation = mIndicationBottomMargin - mIndicationBottomMarginAmbient; + int burnInYOffset = (int) (-mBurnInYOffset + Math.random() * mBurnInYOffset * 2); + mIndicationArea.setTranslationY(dozeTranslation + burnInYOffset); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 492efa2c564f..5a07dbd1eda5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -47,6 +47,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.accessibility.AccessibilityManager; +import android.view.animation.Interpolator; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; @@ -109,17 +110,20 @@ public class NotificationPanelView extends PanelView implements private static final AnimationProperties CLOCK_ANIMATION_PROPERTIES = new AnimationProperties() .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); private static final FloatProperty<NotificationPanelView> SET_DARK_AMOUNT_PROPERTY = - new FloatProperty<NotificationPanelView>("mDarkAmount") { + new FloatProperty<NotificationPanelView>("mInterpolatedDarkAmount") { + @Override public void setValue(NotificationPanelView object, float value) { - object.setDarkAmount(value); + object.setDarkAmount(value, object.mDarkInterpolator.getInterpolation(value)); } @Override public Float get(NotificationPanelView object) { - return object.mDarkAmount; + return object.mLinearDarkAmount; } }; + + private Interpolator mDarkInterpolator; private final PowerManager mPowerManager; private final AccessibilityManager mAccessibilityManager; @@ -239,7 +243,18 @@ public class NotificationPanelView extends PanelView implements private int mIndicationBottomPadding; private int mAmbientIndicationBottomPadding; private boolean mIsFullWidth; - private float mDarkAmount; + + /** + * Current dark amount that follows regular interpolation curve of animation. + */ + private float mInterpolatedDarkAmount; + + /** + * Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the + * interpolation curve is different. + */ + private float mLinearDarkAmount; + private float mDarkAmountTarget; private boolean mPulsing; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); @@ -394,7 +409,7 @@ public class NotificationPanelView extends PanelView implements false); addView(mKeyguardBottomArea, index); initBottomArea(); - setDarkAmount(mDarkAmount); + setDarkAmount(mLinearDarkAmount, mInterpolatedDarkAmount); setKeyguardStatusViewVisibility(mStatusBarState, false, false); setKeyguardBottomAreaVisibility(mStatusBarState, false); @@ -508,7 +523,7 @@ public class NotificationPanelView extends PanelView implements getExpandedFraction(), totalHeight, mKeyguardStatusView.getHeight(), - mDarkAmount, + mInterpolatedDarkAmount, mStatusBar.isKeyguardCurrentlySecure(), mPulsing, mBouncerTop); @@ -1919,7 +1934,7 @@ public class NotificationPanelView extends PanelView implements if (view == null && mQsExpanded) { return; } - if (needsAnimation && mDarkAmount == 0) { + if (needsAnimation && mInterpolatedDarkAmount == 0) { mAnimateNextPositionUpdate = true; } ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone(); @@ -2729,20 +2744,28 @@ public class NotificationPanelView extends PanelView implements } mDarkAmountTarget = darkAmount; if (animate) { + if (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f) { + mDarkInterpolator = dozing + ? Interpolators.FAST_OUT_SLOW_IN + : Interpolators.TOUCH_RESPONSE_REVERSE; + } + mNotificationStackScroller.notifyDarkAnimationStart(dozing); mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, darkAmount); - mDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN); - mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP); + mDarkAnimator.setInterpolator(Interpolators.LINEAR); + mDarkAnimator.setDuration(mNotificationStackScroller.getDarkAnimationDuration(dozing)); mDarkAnimator.start(); } else { - setDarkAmount(darkAmount); + setDarkAmount(darkAmount, darkAmount); } } - private void setDarkAmount(float amount) { - mDarkAmount = amount; - mKeyguardStatusView.setDarkAmount(mDarkAmount); - mKeyguardBottomArea.setDarkAmount(mDarkAmount); + private void setDarkAmount(float linearAmount, float amount) { + mInterpolatedDarkAmount = amount; + mLinearDarkAmount = linearAmount; + mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount); + mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount); positionClockAndNotifications(); + mNotificationStackScroller.setDarkAmount(linearAmount, mInterpolatedDarkAmount); } public void setPulsing(boolean pulsing) { @@ -2767,7 +2790,7 @@ public class NotificationPanelView extends PanelView implements public void dozeTimeTick() { mKeyguardStatusView.dozeTimeTick(); mKeyguardBottomArea.dozeTimeTick(); - if (mDarkAmount > 0) { + if (mInterpolatedDarkAmount > 0) { positionClockAndNotifications(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java index cdbad596051b..19015fcdacf7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java @@ -146,7 +146,7 @@ public enum ScrimState { mAnimationDuration = StatusBar.FADE_KEYGUARD_DURATION; mAnimateChange = !mLaunchingAffordanceWithPreview; - if (previousState == ScrimState.AOD || previousState == ScrimState.PULSING) { + if (previousState == ScrimState.AOD) { // Fade from black to transparent when coming directly from AOD updateScrimColor(mScrimInFront, 1, Color.BLACK); updateScrimColor(mScrimBehind, 1, Color.BLACK); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index ae1da5697321..7cf2c3376e89 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -330,12 +330,6 @@ public class StatusBar extends SystemUI implements DemoMode, /** If true, the lockscreen will show a distinct wallpaper */ private static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true; - /** Whether to force dark theme if Configuration.UI_MODE_NIGHT_YES. */ - private static final boolean DARK_THEME_IN_NIGHT_MODE = true; - - /** Whether to switch the device into night mode in battery saver. */ - private static final boolean NIGHT_MODE_IN_BATTERY_SAVER = true; - /** * Never let the alpha become zero for surfaces that draw with SRC - otherwise the RenderNode * won't draw anything and uninitialized memory will show through @@ -580,7 +574,7 @@ public class StatusBar extends SystemUI implements DemoMode, = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class); private BatteryController mBatteryController; protected boolean mPanelExpanded; - private IOverlayManager mOverlayManager; + private UiModeManager mUiModeManager; private boolean mKeyguardRequested; private boolean mIsKeyguard; private LogMaker mStatusBarStateLog; @@ -641,8 +635,7 @@ public class StatusBar extends SystemUI implements DemoMode, mWakefulnessLifecycle.addObserver(mWakefulnessObserver); mBatteryController = Dependency.get(BatteryController.class); mAssistManager = Dependency.get(AssistManager.class); - mOverlayManager = IOverlayManager.Stub.asInterface( - ServiceManager.getService(Context.OVERLAY_SERVICE)); + mUiModeManager = mContext.getSystemService(UiModeManager.class); mLockscreenUserManager = Dependency.get(NotificationLockscreenUserManager.class); mGutsManager = Dependency.get(NotificationGutsManager.class); mMediaManager = Dependency.get(NotificationMediaManager.class); @@ -948,10 +941,6 @@ public class StatusBar extends SystemUI implements DemoMode, if (mDozeServiceHost != null) { mDozeServiceHost.firePowerSaveChanged(isPowerSave); } - if (NIGHT_MODE_IN_BATTERY_SAVER) { - mContext.getSystemService(UiModeManager.class).setNightMode( - isPowerSave ? UiModeManager.MODE_NIGHT_YES : UiModeManager.MODE_NIGHT_NO); - } } @Override @@ -1199,6 +1188,18 @@ public class StatusBar extends SystemUI implements DemoMode, } } + @Override + public void onUiModeChanged() { + // UiMode will change the style was already evaluated. + // We need to force the re-evaluation to make sure that all parents + // are up to date and new attrs will be rettrieved. + mContext.getTheme().applyStyle(mContext.getThemeResId(), true); + + if (mBrightnessMirrorController != null) { + mBrightnessMirrorController.onUiModeChanged(); + } + } + private void inflateEmptyShadeView() { if (mStackScroller == null) { return; @@ -2099,17 +2100,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateTheme(); } - public boolean isUsingDarkTheme() { - OverlayInfo themeInfo = null; - try { - themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.dark", - mLockscreenUserManager.getCurrentUserId()); - } catch (RemoteException e) { - e.printStackTrace(); - } - return themeInfo != null && themeInfo.isEnabled(); - } - @Nullable public View getAmbientIndicationContainer() { return mAmbientIndicationContainer; @@ -2812,11 +2802,11 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller.dump(fd, pw, args); } pw.println(" Theme:"); - if (mOverlayManager == null) { - pw.println(" overlay manager not initialized!"); - } else { - pw.println(" dark overlay on: " + isUsingDarkTheme()); - } + String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + ""; + pw.println(" dark theme: " + nightMode + + " (auto: " + UiModeManager.MODE_NIGHT_AUTO + + ", yes: " + UiModeManager.MODE_NIGHT_YES + + ", no: " + UiModeManager.MODE_NIGHT_NO + ")"); final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light; pw.println(" light wallpaper theme: " + lightWpTheme); @@ -3149,7 +3139,6 @@ public class StatusBar extends SystemUI implements DemoMode, public void onConfigChanged(Configuration newConfig) { updateResources(); updateDisplaySize(); // populates mDisplayMetrics - updateTheme(); if (DEBUG) { Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); @@ -3887,27 +3876,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected void updateTheme() { final boolean inflated = mStackScroller != null && mStatusBarWindowManager != null; - // The system wallpaper defines if QS should be light or dark. - WallpaperColors systemColors = mColorExtractor - .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); - final boolean wallpaperWantsDarkTheme = systemColors != null - && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; - final Configuration config = mContext.getResources().getConfiguration(); - final boolean nightModeWantsDarkTheme = DARK_THEME_IN_NIGHT_MODE - && (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - final boolean useDarkTheme = wallpaperWantsDarkTheme || nightModeWantsDarkTheme; - if (isUsingDarkTheme() != useDarkTheme) { - mUiOffloadThread.submit(() -> { - try { - mOverlayManager.setEnabled("com.android.systemui.theme.dark", - useDarkTheme, mLockscreenUserManager.getCurrentUserId()); - } catch (RemoteException e) { - Log.w(TAG, "Can't change theme", e); - } - }); - } - // Lock wallpaper defines the color of the majority of the views, hence we'll use it // to set our default theme. final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true @@ -4733,7 +4701,6 @@ public class StatusBar extends SystemUI implements DemoMode, boolean dozing = mDozingRequested && mState == StatusBarState.KEYGUARD || mBiometricUnlockController.getMode() == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING; - final boolean alwaysOn = DozeParameters.getInstance(mContext).getAlwaysOn(); // When in wake-and-unlock we may not have received a change to mState // but we still should not be dozing, manually set to false. if (mBiometricUnlockController.getMode() == @@ -4742,7 +4709,7 @@ public class StatusBar extends SystemUI implements DemoMode, } if (mDozing != dozing) { mDozing = dozing; - mKeyguardViewMediator.setAodShowing(mDozing && alwaysOn); + mKeyguardViewMediator.setAodShowing(mDozing); mStatusBarWindowManager.setDozing(mDozing); mStatusBarKeyguardViewManager.setDozing(mDozing); if (mAmbientIndicationContainer instanceof DozeReceiver) { @@ -4872,6 +4839,7 @@ public class StatusBar extends SystemUI implements DemoMode, } private void setPulsing(boolean pulsing) { + mKeyguardViewMediator.setPulsing(pulsing); mNotificationPanel.setPulsing(pulsing); mVisualStabilityManager.setPulsing(pulsing); mIgnoreTouchWhilePulsing = false; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index fadc0eac9e73..a38328a8161e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -180,6 +180,15 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; } + private void applyExpandedFlag(State state) { + if (state.panelExpanded || state.isKeyguardShowingAndNotOccluded() || state.bouncerShowing + || ENABLE_REMOTE_INPUT && state.remoteInputActive) { + mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED; + } else { + mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED; + } + } + private void applyHeight(State state) { boolean expanded = isExpanded(state); if (state.forcePluginOpen) { @@ -234,6 +243,7 @@ public class StatusBarWindowManager implements RemoteInputController.Callback, D applyKeyguardFlags(state); applyForceStatusBarVisibleFlag(state); applyFocusableFlag(state); + applyExpandedFlag(state); adjustScreenOrientation(state); applyHeight(state); applyUserActivityTimeout(state); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index e9bdc6848ab0..b1986782e914 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.policy; import android.annotation.NonNull; import android.content.res.Resources; import android.util.ArraySet; -import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; @@ -105,11 +104,9 @@ public class BrightnessMirrorController } private void reinflate() { - ContextThemeWrapper qsThemeContext = - new ContextThemeWrapper(mBrightnessMirror.getContext(), R.style.qs_theme); int index = mStatusBarWindow.indexOfChild(mBrightnessMirror); mStatusBarWindow.removeView(mBrightnessMirror); - mBrightnessMirror = LayoutInflater.from(qsThemeContext).inflate( + mBrightnessMirror = LayoutInflater.from(mBrightnessMirror.getContext()).inflate( R.layout.brightness_mirror, mStatusBarWindow, false); mStatusBarWindow.addView(mBrightnessMirror, index); @@ -129,6 +126,10 @@ public class BrightnessMirrorController mBrightnessMirrorListeners.remove(listener); } + public void onUiModeChanged() { + reinflate(); + } + public interface BrightnessMirrorListener { void onBrightnessMirrorReinflated(View brightnessMirror); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java index 3dca371541ef..8c631d9107df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java @@ -28,6 +28,7 @@ public interface ConfigurationController extends CallbackController<Configuratio default void onConfigChanged(Configuration newConfig) {} default void onDensityOrFontScaleChanged() {} default void onOverlayChanged() {} + default void onUiModeChanged() {} default void onLocaleListChanged() {} } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 25261c0ad2ca..f729120f98bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -976,7 +976,7 @@ public class NetworkControllerImpl extends BroadcastReceiver private SubscriptionInfo addSignalController(int id, int simSlotIndex) { SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0, - null, 0, 0, ""); + null, null, null, ""); MobileSignalController controller = new MobileSignalController(mContext, mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info, mSubDefaults, mReceiverHandler.getLooper()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index a4e184b9fa7c..6fc491119aa6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -34,7 +34,6 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.Path; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; @@ -46,11 +45,9 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.core.graphics.ColorUtils; import android.util.AttributeSet; -import android.util.FloatProperty; import android.util.Log; import android.util.MathUtils; import android.util.Pair; -import android.util.Property; import android.view.ContextThemeWrapper; import android.view.InputDevice; import android.view.MotionEvent; @@ -375,25 +372,22 @@ public class NotificationStackScrollLayout extends ViewGroup private boolean mScrollable; private View mForcedScroll; private View mNeedingPulseAnimation; - private float mDarkAmount = 0f; + + /** + * @see #setDarkAmount(float, float) + */ + private float mInterpolatedDarkAmount = 0f; + + /** + * @see #setDarkAmount(float, float) + */ + private float mLinearDarkAmount = 0f; /** * How fast the background scales in the X direction as a factor of the Y expansion. */ private float mBackgroundXFactor = 1f; - private static final Property<NotificationStackScrollLayout, Float> DARK_AMOUNT = - new FloatProperty<NotificationStackScrollLayout>("darkAmount") { - @Override - public void setValue(NotificationStackScrollLayout object, float value) { - object.setDarkAmount(value); - } - @Override - public Float get(NotificationStackScrollLayout object) { - return object.getDarkAmount(); - } - }; - private ObjectAnimator mDarkAmountAnimator; private boolean mUsingLightTheme; private boolean mQsExpanded; private boolean mForwardScrollable; @@ -424,6 +418,8 @@ public class NotificationStackScrollLayout extends ViewGroup private NotificationIconAreaController mIconAreaController; private float mVerticalPanelTranslation; + private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN; + public NotificationStackScrollLayout(Context context) { this(context, null); } @@ -558,16 +554,16 @@ public class NotificationStackScrollLayout extends ViewGroup canvas.drawRect(darkLeft, darkTop, darkRight, darkBottom, mBackgroundPaint); } } else { - float inverseDark = 1 - mDarkAmount; - float yProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(inverseDark); - float xProgress = Interpolators.FAST_OUT_SLOW_IN - .getInterpolation(inverseDark * mBackgroundXFactor); + float yProgress = 1 - mInterpolatedDarkAmount; + float xProgress = mDarkXInterpolator.getInterpolation( + (1 - mLinearDarkAmount) * mBackgroundXFactor); mBackgroundAnimationRect.set( (int) MathUtils.lerp(darkLeft, lockScreenLeft, xProgress), (int) MathUtils.lerp(darkTop, lockScreenTop, yProgress), (int) MathUtils.lerp(darkRight, lockScreenRight, xProgress), (int) MathUtils.lerp(darkBottom, lockScreenBottom, yProgress)); + if (!mAmbientState.isDark() || mFirstVisibleBackgroundChild != null) { canvas.drawRoundRect(mBackgroundAnimationRect.left, mBackgroundAnimationRect.top, mBackgroundAnimationRect.right, mBackgroundAnimationRect.bottom, @@ -585,14 +581,15 @@ public class NotificationStackScrollLayout extends ViewGroup float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount); - alpha *= 1f - mDarkAmount; + alpha *= 1f - mInterpolatedDarkAmount; // We need to manually blend in the background color. int scrimColor = mScrimController.getBackgroundColor(); int awakeColor = ColorUtils.blendARGB(scrimColor, mBgColor, alpha); // Interpolate between semi-transparent notification panel background color // and white AOD separator. - float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation(mDarkAmount); + float colorInterpolation = Interpolators.DECELERATE_QUINT.getInterpolation( + mInterpolatedDarkAmount); int color = ColorUtils.blendARGB(awakeColor, Color.WHITE, colorInterpolation); if (mCachedBackgroundColor != color) { @@ -665,11 +662,15 @@ public class NotificationStackScrollLayout extends ViewGroup int width = MeasureSpec.getSize(widthMeasureSpec); int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2, MeasureSpec.getMode(widthMeasureSpec)); + // Don't constrain the height of the children so we know how big they'd like to be + int childHeightSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), + MeasureSpec.UNSPECIFIED); + // We need to measure all children even the GONE ones, such that the heights are calculated // correctly as they are used to calculate how many we can fit on the screen. final int size = getChildCount(); for (int i = 0; i < size; i++) { - measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec); + measureChild(getChildAt(i), childWidthSpec, childHeightSpec); } } @@ -736,7 +737,8 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updateAlgorithmHeightAndPadding() { - mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, mDarkAmount); + mTopPadding = (int) MathUtils.lerp(mRegularTopPadding, mDarkTopPadding, + mInterpolatedDarkAmount); mAmbientState.setLayoutHeight(getLayoutHeight()); updateAlgorithmLayoutMinHeight(); mAmbientState.setTopPadding(mTopPadding); @@ -961,7 +963,7 @@ public class NotificationStackScrollLayout extends ViewGroup } public void updateClipping() { - boolean animatingClipping = mDarkAmount > 0 && mDarkAmount < 1; + boolean animatingClipping = mInterpolatedDarkAmount > 0 && mInterpolatedDarkAmount < 1; boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode && !mHeadsUpAnimatingAway; if (mIsClipped != clipped) { @@ -2421,7 +2423,7 @@ public class NotificationStackScrollLayout extends ViewGroup return; } - final boolean awake = mDarkAmount != 0 || mAmbientState.isDark(); + final boolean awake = mInterpolatedDarkAmount != 0 || mAmbientState.isDark(); mScrimController.setExcludedBackgroundArea( mFadingOut || mParentNotFullyVisible || awake || mIsClipped ? null : mCurrentBounds); @@ -3413,7 +3415,6 @@ public class NotificationStackScrollLayout extends ViewGroup .animateY(mShelf)); ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex; mAnimationEvents.add(ev); - startDarkAmountAnimation(); } mDarkNeedsAnimation = false; } @@ -3989,11 +3990,8 @@ public class NotificationStackScrollLayout extends ViewGroup if (animate && mAnimationsEnabled) { mDarkNeedsAnimation = true; mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation); - mNeedsAnimation = true; + mNeedsAnimation = true; } else { - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); - } setDarkAmount(dark ? 1f : 0f); updateBackground(); } @@ -4004,7 +4002,7 @@ public class NotificationStackScrollLayout extends ViewGroup } private void updatePanelTranslation() { - setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mDarkAmount); + setTranslationX(mVerticalPanelTranslation + mAntiBurnInOffsetX * mInterpolatedDarkAmount); } public void setVerticalPanelTranslation(float verticalPanelTranslation) { @@ -4023,9 +4021,22 @@ public class NotificationStackScrollLayout extends ViewGroup } private void setDarkAmount(float darkAmount) { - mDarkAmount = darkAmount; + setDarkAmount(darkAmount, darkAmount); + } + + /** + * Sets the current dark amount. + * + * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation, + * i.e. animates from 0 to 1 or vice-versa in a linear manner. + * @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the + * animation curve. + */ + public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) { + mLinearDarkAmount = linearDarkAmount; + mInterpolatedDarkAmount = interpolatedDarkAmount; boolean wasFullyDark = mAmbientState.isFullyDark(); - mAmbientState.setDarkAmount(darkAmount); + mAmbientState.setDarkAmount(interpolatedDarkAmount); boolean nowFullyDark = mAmbientState.isFullyDark(); if (nowFullyDark != wasFullyDark) { updateContentHeight(); @@ -4043,42 +4054,24 @@ public class NotificationStackScrollLayout extends ViewGroup requestChildrenUpdate(); } - public float getDarkAmount() { - return mDarkAmount; - } - - /** - * Cancel any previous dark animations - to avoid race conditions - and creates a new one. - * This function also sets {@code mBackgroundXFactor} based on the current {@code mDarkAmount}. - */ - private void startDarkAmountAnimation() { - boolean dark = mAmbientState.isDark(); - if (mDarkAmountAnimator != null) { - mDarkAmountAnimator.cancel(); + public void notifyDarkAnimationStart(boolean dark) { + // We only swap the scaling factor if we're fully dark or fully awake to avoid + // interpolation issues when playing with the power button. + if (mInterpolatedDarkAmount == 0 || mInterpolatedDarkAmount == 1) { + mBackgroundXFactor = dark ? 1.8f : 1.5f; + mDarkXInterpolator = dark + ? Interpolators.FAST_OUT_SLOW_IN_REVERSE + : Interpolators.FAST_OUT_SLOW_IN; } + } + public long getDarkAnimationDuration(boolean dark) { long duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP; // Longer animation when sleeping with more than 1 notification if (dark && getNotGoneChildCount() > 2) { duration *= 1.2f; } - - mDarkAmountAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount, - dark ? 1f : 0); - // We only swap the scaling factor if we're fully dark or fully awake to avoid - // interpolation issues when playing with the power button. - if (mDarkAmount == 0 || mDarkAmount == 1) { - mBackgroundXFactor = dark ? 2.5f : 1.5f; - } - mDarkAmountAnimator.setDuration(duration); - mDarkAmountAnimator.setInterpolator(Interpolators.LINEAR); - mDarkAmountAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mDarkAmountAnimator = null; - } - }); - mDarkAmountAnimator.start(); + return duration; } private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) { diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java index a901e88219a5..b83590979ef7 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java @@ -23,7 +23,7 @@ import android.os.Handler; */ public class DelayedWakeLock implements WakeLock { - private static final long RELEASE_DELAY_MS = 140; + private static final long RELEASE_DELAY_MS = 100; private final Handler mHandler; private final WakeLock mInner; diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java index dd552646955a..2861dffe5460 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java @@ -61,7 +61,7 @@ public class VolumeDialogComponent implements VolumeComponent, TunerService.Tuna private final VolumeDialogControllerImpl mController; private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges( ActivityInfo.CONFIG_FONT_SCALE | ActivityInfo.CONFIG_LOCALE - | ActivityInfo.CONFIG_ASSETS_PATHS); + | ActivityInfo.CONFIG_ASSETS_PATHS | ActivityInfo.CONFIG_UI_MODE); private VolumeDialog mDialog; private VolumePolicy mVolumePolicy = new VolumePolicy( DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT, // volumeDownToEnterSilent diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml index 80d8066959af..9254b4d65b50 100644 --- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/config.xml @@ -37,6 +37,8 @@ @right </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml index ca261f98cfae..80c997a46264 100644 --- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/config.xml @@ -49,6 +49,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml index c22b2e778ff1..6fb3c7f51e26 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml index 401e09211ae7..7c29ffb92f4e 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml index f328b83c1cbf..5fb8b9e241b8 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml @@ -40,6 +40,8 @@ @dp </string> + <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">@*android:string/config_mainBuiltInDisplayCutout</string> + <!-- Whether the display cutout region of the main built-in display should be forced to black in software (to avoid aliasing or emulate a cutout that is not physically existent). --> diff --git a/packages/overlays/SysuiDarkThemeOverlay/Android.mk b/packages/overlays/SysuiDarkThemeOverlay/Android.mk deleted file mode 100644 index 7b277bcf0351..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/Android.mk +++ /dev/null @@ -1,14 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_RRO_THEME := SysuiDarkTheme -LOCAL_CERTIFICATE := platform - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := SysuiDarkThemeOverlay -LOCAL_SDK_VERSION := current - -include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml deleted file mode 100644 index 8b6ee2bb851c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.systemui.theme.dark" - android:versionCode="1" - android:versionName="1.0"> - <overlay android:targetPackage="com.android.systemui" android:priority="1"/> - - <application android:label="@string/sysui_overlay_dark" android:hasCode="false"/> -</manifest> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-af/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-af/strings.xml deleted file mode 100644 index 33c6982e007a..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-af/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Donker"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-am/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-am/strings.xml deleted file mode 100644 index 59795695251b..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-am/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ጨለማ"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ar/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ar/strings.xml deleted file mode 100644 index 7b20c01957aa..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ar/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"داكن"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-as/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-as/strings.xml deleted file mode 100644 index 0910e7e753cb..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-as/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"গাঢ়"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-az/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-az/strings.xml deleted file mode 100644 index a9db75cdb525..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-az/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Qaranlıq"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-b+sr+Latn/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-b+sr+Latn/strings.xml deleted file mode 100644 index b63dcbcaa88e..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-b+sr+Latn/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tamno"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-be/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-be/strings.xml deleted file mode 100644 index eb875b3e8035..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-be/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Цёмная"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-bg/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-bg/strings.xml deleted file mode 100644 index 7b39462ffc25..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-bg/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Тъмно"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-bn/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-bn/strings.xml deleted file mode 100644 index 0910e7e753cb..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-bn/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"গাঢ়"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-bs/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-bs/strings.xml deleted file mode 100644 index b63dcbcaa88e..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-bs/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tamno"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ca/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ca/strings.xml deleted file mode 100644 index 02ee2268bb83..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ca/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Fosc"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-cs/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-cs/strings.xml deleted file mode 100644 index 5d11f07d9948..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-cs/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tmavé"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-da/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-da/strings.xml deleted file mode 100644 index 460ebe7739bc..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-da/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Mørk"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-de/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-de/strings.xml deleted file mode 100644 index 4b54b8e11920..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-de/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dunkel"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-el/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-el/strings.xml deleted file mode 100644 index c58061dab337..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-el/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Σκοτεινό"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rAU/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rAU/strings.xml deleted file mode 100644 index 7c94a51ded3c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rAU/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dark"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rCA/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rCA/strings.xml deleted file mode 100644 index 7c94a51ded3c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rCA/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dark"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rGB/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rGB/strings.xml deleted file mode 100644 index 7c94a51ded3c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rGB/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dark"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rIN/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rIN/strings.xml deleted file mode 100644 index 7c94a51ded3c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rIN/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dark"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rXC/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rXC/strings.xml deleted file mode 100644 index cbdd3d2030b4..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-en-rXC/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dark"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-es-rUS/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-es-rUS/strings.xml deleted file mode 100644 index 2717f0f879c5..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-es-rUS/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Oscuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-es/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-es/strings.xml deleted file mode 100644 index 2717f0f879c5..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-es/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Oscuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-et/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-et/strings.xml deleted file mode 100644 index e0cce054fc07..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-et/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tume"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-eu/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-eu/strings.xml deleted file mode 100644 index 44cee4cf9da4..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-eu/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Iluna"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-fa/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-fa/strings.xml deleted file mode 100644 index fdd1df54bfff..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-fa/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"تیره"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-fi/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-fi/strings.xml deleted file mode 100644 index 237fe70ff91d..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-fi/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tumma"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-fr-rCA/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-fr-rCA/strings.xml deleted file mode 100644 index f92c2ef95af3..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-fr-rCA/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Sombre"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-fr/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-fr/strings.xml deleted file mode 100644 index eac51d3a4fbf..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-fr/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Foncé"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-gl/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-gl/strings.xml deleted file mode 100644 index 300868f871e2..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-gl/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Escuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-gu/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-gu/strings.xml deleted file mode 100644 index 6a4cd62ff26f..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-gu/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ઘેરી"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-hi/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-hi/strings.xml deleted file mode 100644 index c5bc0e24ed5c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-hi/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"गहरे रंग की थीम"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-hr/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-hr/strings.xml deleted file mode 100644 index b63dcbcaa88e..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-hr/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tamno"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-hu/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-hu/strings.xml deleted file mode 100644 index 84a3ab87c721..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-hu/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Sötét"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-hy/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-hy/strings.xml deleted file mode 100644 index 555cb647083e..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-hy/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Մուգ"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-in/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-in/strings.xml deleted file mode 100644 index 391451bc3afe..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-in/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Gelap"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-is/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-is/strings.xml deleted file mode 100644 index f4d15311c951..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-is/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Dökkt"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-it/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-it/strings.xml deleted file mode 100644 index b59155bda97a..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-it/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Scuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-iw/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-iw/strings.xml deleted file mode 100644 index 3ecf444fcbb0..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-iw/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"כהה"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ja/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ja/strings.xml deleted file mode 100644 index 3a2dba02f501..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ja/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ダーク"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ka/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ka/strings.xml deleted file mode 100644 index 36bf77e1c8a4..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ka/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"მუქი"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-kk/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-kk/strings.xml deleted file mode 100644 index 913c0b18448d..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-kk/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Қараңғы"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-km/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-km/strings.xml deleted file mode 100644 index b56c4909fbc7..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-km/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ងងឹត"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-kn/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-kn/strings.xml deleted file mode 100644 index e75711668387..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-kn/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ಕತ್ತಲೆ"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ko/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ko/strings.xml deleted file mode 100644 index ca4ab1e283ae..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ko/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"어두움"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ky/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ky/strings.xml deleted file mode 100644 index e8e827972a04..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ky/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Караңгы"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-lo/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-lo/strings.xml deleted file mode 100644 index 0434a413fb7f..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-lo/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ມືດ"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-lt/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-lt/strings.xml deleted file mode 100644 index 147779b850f4..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-lt/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tamsi"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-lv/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-lv/strings.xml deleted file mode 100644 index 7a296ecda7f3..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-lv/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tumšs"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-mk/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-mk/strings.xml deleted file mode 100644 index 6be693af1219..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-mk/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Темна"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ml/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ml/strings.xml deleted file mode 100644 index f8a24fa4af66..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ml/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ഡാർക്ക്"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-mn/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-mn/strings.xml deleted file mode 100644 index e65d9c70c07d..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-mn/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Бараан"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-mr/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-mr/strings.xml deleted file mode 100644 index 854af000ab0f..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-mr/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"गडद"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ms/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ms/strings.xml deleted file mode 100644 index 391451bc3afe..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ms/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Gelap"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-my/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-my/strings.xml deleted file mode 100644 index 008e9c694a98..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-my/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"မှောင်သော"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-nb/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-nb/strings.xml deleted file mode 100644 index 460ebe7739bc..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-nb/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Mørk"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ne/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ne/strings.xml deleted file mode 100644 index 8f2c5ba89732..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ne/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"अँध्यारो"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-nl/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-nl/strings.xml deleted file mode 100644 index 33c6982e007a..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-nl/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Donker"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-or/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-or/strings.xml deleted file mode 100644 index d8045bd6de6e..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-or/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ଗାଢ଼"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-pa/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-pa/strings.xml deleted file mode 100644 index 71103030493a..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-pa/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ਗੂੜ੍ਹਾ"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-pl/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-pl/strings.xml deleted file mode 100644 index 25ca20fe421d..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-pl/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Ciemna"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rBR/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rBR/strings.xml deleted file mode 100644 index 300868f871e2..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rBR/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Escuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rPT/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rPT/strings.xml deleted file mode 100644 index 300868f871e2..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt-rPT/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Escuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-pt/strings.xml deleted file mode 100644 index 300868f871e2..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-pt/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Escuro"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ro/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ro/strings.xml deleted file mode 100644 index de73f36e6b83..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ro/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Întunecată"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ru/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ru/strings.xml deleted file mode 100644 index b05e84454c68..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ru/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Темный"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-si/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-si/strings.xml deleted file mode 100644 index f0f572502f5f..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-si/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"අඳුරු"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sk/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sk/strings.xml deleted file mode 100644 index 5df68959b1a2..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sk/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tmavý"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sl/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sl/strings.xml deleted file mode 100644 index ad58250a117c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sl/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Temno"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sq/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sq/strings.xml deleted file mode 100644 index 0e1eae7064b6..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sq/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"E errët"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sr/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sr/strings.xml deleted file mode 100644 index 1561ee298a2c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sr/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Тамно"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sv/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sv/strings.xml deleted file mode 100644 index 676de42dceb1..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sv/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Mörk"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-sw/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-sw/strings.xml deleted file mode 100644 index cc1f120adfc1..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-sw/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Nyeusi"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ta/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ta/strings.xml deleted file mode 100644 index af98172472d4..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ta/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"டார்க்"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-te/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-te/strings.xml deleted file mode 100644 index 446455fe7dd8..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-te/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"ముదురు రంగు"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-th/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-th/strings.xml deleted file mode 100644 index 9e3462b61e4b..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-th/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"เข้ม"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-tl/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-tl/strings.xml deleted file mode 100644 index 5502d90a889c..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-tl/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Madilim"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-tr/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-tr/strings.xml deleted file mode 100644 index 368b398bcf17..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-tr/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Koyu"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-uk/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-uk/strings.xml deleted file mode 100644 index 6e67e455e95d..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-uk/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Темна тема"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-ur/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-ur/strings.xml deleted file mode 100644 index 1d5d6de407b3..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-ur/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"گہرا"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-uz/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-uz/strings.xml deleted file mode 100644 index 957c28f8fb04..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-uz/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tungi"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-vi/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-vi/strings.xml deleted file mode 100644 index a45888955988..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-vi/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Tối"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rCN/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rCN/strings.xml deleted file mode 100644 index c9b43dcba4ea..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rCN/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"深色"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rHK/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rHK/strings.xml deleted file mode 100644 index c9b43dcba4ea..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rHK/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"深色"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rTW/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rTW/strings.xml deleted file mode 100644 index c9b43dcba4ea..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-zh-rTW/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"深色"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values-zu/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values-zu/strings.xml deleted file mode 100644 index 6d328da358a7..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values-zu/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * 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. - */ - --> - -<resources xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="sysui_overlay_dark" msgid="557336259295713662">"Emnyama"</string> -</resources> diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/strings.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/strings.xml deleted file mode 100644 index 71f48d6279f1..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values/strings.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/** - * 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. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - - <string name="sysui_overlay_dark">Dark</string> - -</resources> - diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml deleted file mode 100644 index 41a294092648..000000000000 --- a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="qs_base" parent="android:Theme.DeviceDefault"> - <item name="android:colorPrimary">@*android:color/primary_device_default_settings</item> - <item name="android:colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item> - <item name="android:colorSecondary">@*android:color/secondary_device_default_settings</item> - <item name="android:colorAccent">@*android:color/accent_device_default_dark</item> - <item name="android:colorControlNormal">?android:attr/textColorPrimary</item> - <item name="android:colorBackgroundFloating">@*android:color/material_grey_900</item> - <item name="android:panelColorBackground">@*android:color/material_grey_800</item> - </style> -</resources>
\ No newline at end of file diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto index 33fc5e52c74d..15c04681e38f 100644 --- a/proto/src/wifi.proto +++ b/proto/src/wifi.proto @@ -470,6 +470,9 @@ message WifiLog { // Counts the occurrences of each link speed (Mbps) level // with rssi (dBm) and rssi^2 sums (dBm^2) repeated LinkSpeedCount link_speed_counts = 121; + + // Number of times the SarManager failed to register SAR sensor listener + optional int32 num_sar_sensor_registration_failures = 122; } // Information that gets logged for every WiFi connection. @@ -1611,4 +1614,4 @@ message WifiIsUnusableEvent { // Firmware alert code. Only valid when the event was triggered by a firmware alert, otherwise -1. optional int32 firmware_alert_code = 10 [default = -1]; -}
\ No newline at end of file +} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java index 105df9238f8d..8f921454196f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java @@ -258,6 +258,7 @@ class AccessibilityServiceConnection extends AbstractAccessibilityServiceConnect return; } mWasConnectedAndDied = true; + mSystemSupport.getKeyEventDispatcher().flush(this); UserState userState = mUserStateWeakReference.get(); if (userState != null) { userState.serviceDisconnectedLocked(this); diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index cc5acdf5abfa..7185f025ba8c 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -2690,7 +2690,7 @@ class AlarmManagerService extends SystemService { errorMsg.append("[mNextNonWakeup="); TimeUtils.formatDuration(mNextNonWakeup - nowElapsed, errorMsg); errorMsg.append(" set at "); - TimeUtils.formatDuration(mNextNonWakeUpSetAt, errorMsg); + TimeUtils.formatDuration(mNextNonWakeUpSetAt - nowElapsed, errorMsg); errorMsg.append(", mLastWakeup="); TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg); errorMsg.append(", timerfd_gettime=" + getNextAlarm(mNativeData, ELAPSED_REALTIME)); @@ -2701,7 +2701,7 @@ class AlarmManagerService extends SystemService { errorMsg.append("[mNextWakeup="); TimeUtils.formatDuration(mNextWakeup - nowElapsed, errorMsg); errorMsg.append(" set at "); - TimeUtils.formatDuration(mNextWakeUpSetAt, errorMsg); + TimeUtils.formatDuration(mNextWakeUpSetAt - nowElapsed, errorMsg); errorMsg.append(", mLastWakeup="); TimeUtils.formatDuration(mLastWakeup - nowElapsed, errorMsg); errorMsg.append(", timerfd_gettime=" diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 1167e1d41a9c..b3f6bd1d41cc 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -22,6 +22,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.AppOpsManagerInternal; +import android.app.AppOpsManagerInternal.CheckOpsDelegate; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -207,6 +208,8 @@ public class AppOpsService extends IAppOpsService.Stub { SparseIntArray mProfileOwners; + private CheckOpsDelegate mCheckOpsDelegate; + /** * All times are in milliseconds. These constants are kept synchronized with the system * global Settings. Any access to this class or its fields should be done while @@ -1411,15 +1414,39 @@ public class AppOpsService extends IAppOpsService.Stub { } } + public CheckOpsDelegate getAppOpsServiceDelegate() { + synchronized (this) { + return mCheckOpsDelegate; + } + } + + public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) { + synchronized (this) { + mCheckOpsDelegate = delegate; + } + } + @Override public int checkOperation(int code, int uid, String packageName) { - verifyIncomingUid(uid); - verifyIncomingOp(code); - String resolvedPackageName = resolvePackageName(uid, packageName); - if (resolvedPackageName == null) { - return AppOpsManager.MODE_IGNORED; + final CheckOpsDelegate delegate; + synchronized (this) { + if (mCheckOpsDelegate == null) { + return checkOperationImpl(code, uid, packageName); + } + delegate = mCheckOpsDelegate; } + return delegate.checkOperation(code, uid, packageName, + AppOpsService.this::checkOperationImpl); + } + + private int checkOperationImpl(int code, int uid, String packageName) { synchronized (this) { + verifyIncomingUid(uid); + verifyIncomingOp(code); + String resolvedPackageName = resolvePackageName(uid, packageName); + if (resolvedPackageName == null) { + return AppOpsManager.MODE_IGNORED; + } if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { return AppOpsManager.MODE_IGNORED; } @@ -1439,20 +1466,33 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int checkAudioOperation(int code, int usage, int uid, String packageName) { - boolean suspended; - try { - suspended = isPackageSuspendedForUser(packageName, uid); - } catch (IllegalArgumentException ex) { - // Package not found. - suspended = false; - } - - if (suspended) { - Slog.i(TAG, "Audio disabled for suspended package=" + packageName + " for uid=" + uid); - return AppOpsManager.MODE_IGNORED; + final CheckOpsDelegate delegate; + synchronized (this) { + if (mCheckOpsDelegate == null) { + return checkAudioOperationImpl(code, usage, uid, packageName); + } + delegate = mCheckOpsDelegate; } + return delegate.checkAudioOperation(code, usage, uid, packageName, + AppOpsService.this::checkAudioOperationImpl); + } + private int checkAudioOperationImpl(int code, int usage, int uid, String packageName) { synchronized (this) { + boolean suspended; + try { + suspended = isPackageSuspendedForUser(packageName, uid); + } catch (IllegalArgumentException ex) { + // Package not found. + suspended = false; + } + + if (suspended) { + Slog.i(TAG, "Audio disabled for suspended package=" + packageName + + " for uid=" + uid); + return AppOpsManager.MODE_IGNORED; + } + final int mode = checkRestrictionLocked(code, usage, uid, packageName); if (mode != AppOpsManager.MODE_ALLOWED) { return mode; @@ -1530,10 +1570,10 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public int noteProxyOperation(int code, String proxyPackageName, - int proxiedUid, String proxiedPackageName) { + public int noteProxyOperation(int code, int proxyUid, + String proxyPackageName, int proxiedUid, String proxiedPackageName) { + verifyIncomingUid(proxyUid); verifyIncomingOp(code); - final int proxyUid = Binder.getCallingUid(); String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName); if (resolveProxyPackageName == null) { return AppOpsManager.MODE_IGNORED; @@ -1553,6 +1593,18 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int noteOperation(int code, int uid, String packageName) { + final CheckOpsDelegate delegate; + synchronized (this) { + if (mCheckOpsDelegate == null) { + return noteOperationImpl(code, uid, packageName); + } + delegate = mCheckOpsDelegate; + } + return delegate.noteOperation(code, uid, packageName, + AppOpsService.this::noteOperationImpl); + } + + private int noteOperationImpl(int code, int uid, String packageName) { verifyIncomingUid(uid); verifyIncomingOp(code); String resolvedPackageName = resolvePackageName(uid, packageName); diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java index ce1be6f63e2b..3d779d80b9a1 100644 --- a/services/core/java/com/android/server/BinderCallsStatsService.java +++ b/services/core/java/com/android/server/BinderCallsStatsService.java @@ -17,15 +17,20 @@ package com.android.server; import android.app.AppGlobals; +import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.database.ContentObserver; +import android.net.Uri; import android.os.Binder; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; +import android.provider.Settings; +import android.util.KeyValueListParser; import android.util.Slog; +import com.android.internal.os.BackgroundThread; import com.android.internal.os.BinderCallsStats; import java.io.FileDescriptor; @@ -41,20 +46,92 @@ public class BinderCallsStatsService extends Binder { private static final String PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING = "persist.sys.binder_calls_detailed_tracking"; - public static void start() { - BinderCallsStatsService service = new BinderCallsStatsService(); - ServiceManager.addService("binder_calls_stats", service); - boolean detailedTrackingEnabled = SystemProperties.getBoolean( - PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, false); - - if (detailedTrackingEnabled) { - Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by " - + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING - + " or via dumpsys binder_calls_stats --enable-detailed-tracking"); - BinderCallsStats.getInstance().setDetailedTracking(true); + /** Listens for flag changes. */ + private static class SettingsObserver extends ContentObserver { + private static final String SETTINGS_ENABLED_KEY = "enabled"; + private static final String SETTINGS_DETAILED_TRACKING_KEY = "detailed_tracking"; + private static final String SETTINGS_UPLOAD_DATA_KEY = "upload_data"; + private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval"; + + private final Uri mUri = Settings.Global.getUriFor(Settings.Global.BINDER_CALLS_STATS); + private final Context mContext; + private final KeyValueListParser mParser = new KeyValueListParser(','); + + public SettingsObserver(Context context) { + super(BackgroundThread.getHandler()); + mContext = context; + context.getContentResolver().registerContentObserver(mUri, false, this, + UserHandle.USER_SYSTEM); + // Always kick once to ensure that we match current state + onChange(); + } + + @Override + public void onChange(boolean selfChange, Uri uri, int userId) { + if (mUri.equals(uri)) { + onChange(); + } + } + + public void onChange() { + // Do not overwrite the default set manually. + if (!SystemProperties.get(PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING).isEmpty()) { + return; + } + + BinderCallsStats stats = BinderCallsStats.getInstance(); + try { + mParser.setString(Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.BINDER_CALLS_STATS)); + } catch (IllegalArgumentException e) { + Slog.e(TAG, "Bad binder call stats settings", e); + } + stats.setEnabled( + mParser.getBoolean(SETTINGS_ENABLED_KEY, BinderCallsStats.ENABLED_DEFAULT)); + stats.setDetailedTracking(mParser.getBoolean( + SETTINGS_DETAILED_TRACKING_KEY, BinderCallsStats.DETAILED_TRACKING_DEFAULT)); + stats.setSamplingInterval(mParser.getInt( + SETTINGS_SAMPLING_INTERVAL_KEY, + BinderCallsStats.PERIODIC_SAMPLING_INTERVAL_DEFAULT)); } } + public static class LifeCycle extends SystemService { + private BinderCallsStatsService mService; + + public LifeCycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new BinderCallsStatsService(); + publishBinderService("binder_calls_stats", mService); + boolean detailedTrackingEnabled = SystemProperties.getBoolean( + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING, false); + + if (detailedTrackingEnabled) { + Slog.i(TAG, "Enabled CPU usage tracking for binder calls. Controlled by " + + PERSIST_SYS_BINDER_CALLS_DETAILED_TRACKING + + " or via dumpsys binder_calls_stats --enable-detailed-tracking"); + BinderCallsStats.getInstance().setDetailedTracking(true); + } + } + + @Override + public void onBootPhase(int phase) { + if (SystemService.PHASE_SYSTEM_SERVICES_READY == phase) { + mService.systemReady(getContext()); + } + } + } + + private SettingsObserver mSettingsObserver; + + public void systemReady(Context context) { + mSettingsObserver = new SettingsObserver(context); + } + public static void reset() { Slog.i(TAG, "Resetting stats"); BinderCallsStats.getInstance().reset(); @@ -106,7 +183,13 @@ public class BinderCallsStatsService extends Binder { } Map<Integer,String> map = new HashMap<>(); for (PackageInfo pkg : packages) { - map.put(pkg.applicationInfo.uid, pkg.packageName); + String name = pkg.packageName; + int uid = pkg.applicationInfo.uid; + // Use sharedUserId string as package name if there are collisions + if (pkg.sharedUserId != null && map.containsKey(uid)) { + name = "shared:" + pkg.sharedUserId; + } + map.put(uid, name); } return map; } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index aa426d3cd31f..78b738500a97 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -53,12 +53,16 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.text.TextUtils; +import android.util.FeatureFlagUtils; +import android.util.Log; import android.util.Slog; import android.util.StatsLog; @@ -386,6 +390,15 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>(); mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>(); + // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils + boolean isHearingAidEnabled; + String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS); + if (!TextUtils.isEmpty(value)) { + isHearingAidEnabled = Boolean.parseBoolean(value); + Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled); + FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled); + } + IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3c94a344b430..2054e0a97e35 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2229,6 +2229,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateCapabilities(oldScore, nai, nai.networkCapabilities); // If score has changed, rebroadcast to NetworkFactories. b/17726566 if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai); + if (valid) handleFreshlyValidatedNetwork(nai); } updateInetCondition(nai); // Let the NetworkAgent know the state of its network @@ -2323,6 +2324,16 @@ public class ConnectivityService extends IConnectivityManager.Stub mDefaultRequest.networkCapabilities, nai.networkCapabilities); } + private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) { + if (nai == null) return; + // If the Private DNS mode is opportunistic, reprogram the DNS servers + // in order to restart a validation pass from within netd. + final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig(); + if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) { + updateDnses(nai.linkProperties, null, nai.network.netId); + } + } + private void handlePrivateDnsSettingsChanged() { final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig(); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 96ac71224bb9..9c55de7ec72d 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -539,6 +539,11 @@ public final class ActiveServices { if (fgRequired) { // We are now effectively running a foreground service. + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(true, mAm.mProcessStats.getMemFactorLocked(), + r.lastActivity); + } mAm.mAppOpsService.startOperation(AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, true); } @@ -1190,13 +1195,14 @@ public final class ActiveServices { r.app.pid, r.appInfo.uid, "startForeground"); } boolean alreadyStartedOp = false; + boolean stopProcStatsOp = false; if (r.fgRequired) { if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) { Slog.i(TAG, "Service called startForeground() as required: " + r); } r.fgRequired = false; r.fgWaiting = false; - alreadyStartedOp = true; + alreadyStartedOp = stopProcStatsOp = true; mAm.mHandler.removeMessages( ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r); } @@ -1264,6 +1270,15 @@ public final class ActiveServices { active.mNumActive++; } r.isForeground = true; + if (!stopProcStatsOp) { + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(true, + mAm.mProcessStats.getMemFactorLocked(), r.lastActivity); + } + } else { + stopProcStatsOp = false; + } mAm.mAppOpsService.startOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, @@ -1285,6 +1300,15 @@ public final class ActiveServices { } } } finally { + if (stopProcStatsOp) { + // We got through to this point with it actively being started foreground, + // and never decided we wanted to keep it like that, so drop it. + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), + r.lastActivity); + } + } if (alreadyStartedOp) { // If we had previously done a start op for direct foreground start, // we have cleared the flag so can now drop it. @@ -1300,6 +1324,11 @@ public final class ActiveServices { decActiveForegroundAppLocked(smap, r); } r.isForeground = false; + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), + r.lastActivity); + } mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName); @@ -1598,7 +1627,7 @@ public final class ActiveServices { } mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState, - s.appInfo.uid, s.name, s.processName); + s.appInfo.uid, s.appInfo.longVersionCode, s.name, s.processName); // Once the apps have become associated, if one of them is caller is ephemeral // the target app should now be able to see the calling app mAm.grantEphemeralAccessLocked(callerApp.userId, service, @@ -1606,7 +1635,8 @@ public final class ActiveServices { AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, - connection, flags, clientLabel, clientIntent); + connection, flags, clientLabel, clientIntent, + callerApp.uid, callerApp.processName); IBinder binder = connection.asBinder(); ArrayList<ConnectionRecord> clist = s.connections.get(binder); @@ -1623,6 +1653,7 @@ public final class ActiveServices { activity.connections.add(c); } b.client.connections.add(c); + c.startAssociationIfNeeded(); if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) { b.client.hasAboveClient = true; } @@ -2437,7 +2468,7 @@ public final class ActiveServices { if (DEBUG_MU) Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid + ", ProcessRecord.uid = " + app.uid); - r.app = app; + r.setProcess(app); r.restartTime = r.lastActivity = SystemClock.uptimeMillis(); final boolean newService = app.services.add(r); @@ -2479,7 +2510,7 @@ public final class ActiveServices { // Cleanup. if (newService) { app.services.remove(r); - r.app = null; + r.setProcess(null); } // Retry. @@ -2663,6 +2694,7 @@ public final class ActiveServices { // There is still a connection to the service that is // being brought down. Mark it as dead. cr.serviceDead = true; + cr.stopAssociation(); try { cr.conn.connected(r.name, null, true); } catch (Exception e) { @@ -2703,6 +2735,11 @@ public final class ActiveServices { + r); r.fgRequired = false; r.fgWaiting = false; + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), + r.lastActivity); + } mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName); mAm.mHandler.removeMessages( @@ -2755,6 +2792,11 @@ public final class ActiveServices { cancelForegroundNotificationLocked(r); if (r.isForeground) { decActiveForegroundAppLocked(smap, r); + ServiceState stracker = r.getTracker(); + if (stracker != null) { + stracker.setForeground(false, mAm.mProcessStats.getMemFactorLocked(), + r.lastActivity); + } mAm.mAppOpsService.finishOperation( AppOpsManager.getToken(mAm.mAppOpsService), AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName); @@ -2835,6 +2877,7 @@ public final class ActiveServices { } } b.connections.remove(c); + c.stopAssociation(); if (c.activity != null && c.activity != skipAct) { if (c.activity.connections != null) { c.activity.connections.remove(c); @@ -2865,7 +2908,8 @@ public final class ActiveServices { } } - mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name); + mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, + s.appInfo.longVersionCode, s.name, s.processName); if (b.connections.size() == 0) { b.intent.apps.remove(b.client); @@ -3056,7 +3100,7 @@ public final class ActiveServices { updateWhitelistManagerLocked(r.app); } } - r.app = null; + r.setProcess(null); } } } @@ -3155,7 +3199,7 @@ public final class ActiveServices { } } } - service.app = null; + service.setProcess(null); service.isolatedProc = null; if (mTmpCollectionResults == null) { mTmpCollectionResults = new ArrayList<>(); @@ -3305,7 +3349,7 @@ public final class ActiveServices { if (sr.app != app && sr.app != null && !sr.app.isPersistent()) { sr.app.services.remove(sr); } - sr.app = null; + sr.setProcess(null); sr.isolatedProc = null; sr.executeNesting = 0; sr.forceClearTracker(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b1abbf1279a6..b31c8db3c54e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -86,7 +86,6 @@ import static android.os.Process.setThreadPriority; import static android.os.Process.setThreadScheduler; import static android.os.Process.startWebView; import static android.os.Process.zygoteProcess; -import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS; @@ -164,9 +163,9 @@ import android.app.ActivityManagerInternal; import android.app.ActivityManagerProto; import android.app.ActivityOptions; import android.app.ActivityThread; -import android.app.AlertDialog; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.AppOpsManagerInternal.CheckOpsDelegate; import android.app.ApplicationErrorReport; import android.app.ApplicationThreadConstants; import android.app.BroadcastOptions; @@ -205,7 +204,6 @@ import android.content.ComponentName; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; -import android.content.DialogInterface; import android.content.IContentProvider; import android.content.IIntentReceiver; import android.content.IIntentSender; @@ -222,6 +220,7 @@ import android.content.pm.PackageInfo; 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.ParceledListSlice; import android.content.pm.PathPermission; import android.content.pm.PermissionInfo; @@ -260,7 +259,6 @@ import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.ParcelFileDescriptor; -import android.os.PowerManager; import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.Process; @@ -283,7 +281,6 @@ import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; import android.provider.Downloads; import android.provider.Settings; -import android.service.voice.IVoiceInteractionSession; import android.text.TextUtils; import android.text.format.DateUtils; import android.text.style.SuggestionSpan; @@ -321,7 +318,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.DumpHeapActivity; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; -import com.android.internal.app.IVoiceInteractor; import com.android.internal.app.ProcessMap; import com.android.internal.app.SystemUserHomeActivity; import com.android.internal.app.procstats.ProcessStats; @@ -342,6 +338,8 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.TriFunction; import com.android.server.AlarmManagerInternal; import com.android.server.AppOpsService; import com.android.server.AttributeCache; @@ -359,21 +357,9 @@ import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.ThreadPriorityBooster; import com.android.server.Watchdog; -import com.android.server.am.ActivityManagerServiceDumpActivitiesProto; -import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto; -import com.android.server.am.ActivityManagerServiceDumpProcessesProto; import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto; -import com.android.server.am.ActivityManagerServiceDumpServicesProto; -import com.android.server.am.ActivityManagerServiceProto; import com.android.server.am.ActivityStack.ActivityState; -import com.android.server.am.GrantUriProto; -import com.android.server.am.ImportanceTokenProto; -import com.android.server.am.MemInfoDumpProto; import com.android.server.am.MemoryStatUtil.MemoryStat; -import com.android.server.am.NeededUriGrantsProto; -import com.android.server.am.ProcessOomProto; -import com.android.server.am.ProcessToGcProto; -import com.android.server.am.StickyBroadcastProto; import com.android.server.firewall.IntentFirewall; import com.android.server.job.JobSchedulerInternal; import com.android.server.pm.Installer; @@ -382,7 +368,6 @@ import com.android.server.pm.dex.DexManager; import com.android.server.utils.PriorityDump; import com.android.server.vr.VrManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; -import com.android.server.wm.ActivityTaskManagerInternal.SleepToken; import com.android.server.wm.WindowManagerService; import org.xmlpull.v1.XmlPullParser; @@ -422,6 +407,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -580,8 +566,6 @@ public class ActivityManagerService extends IActivityManager.Stub // Whether we should use SCHED_FIFO for UI and RenderThreads. private boolean mUseFifoUiScheduling = false; - private static final String SYSUI_COMPONENT_NAME = "com.android.systemui/.SystemUIService"; - BroadcastQueue mFgBroadcastQueue; BroadcastQueue mBgBroadcastQueue; // Convenient for easy iteration over the queues. Foreground is first @@ -638,7 +622,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean asProto) { if (asProto) return; doDump(fd, pw, new String[]{"activities"}, asProto); - doDump(fd, pw, new String[]{"service", SYSUI_COMPONENT_NAME}, asProto); + doDump(fd, pw, new String[]{"service", "all-platform-critical"}, asProto); } @Override @@ -9016,7 +9000,8 @@ public class ActivityManagerService extends IActivityManager.Stub } ContentProviderConnection incProviderCountLocked(ProcessRecord r, - final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) { + final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid, + String callingTag, boolean stable) { if (r != null) { for (int i=0; i<r.conProviders.size(); i++) { ContentProviderConnection conn = r.conProviders.get(i); @@ -9037,6 +9022,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } ContentProviderConnection conn = new ContentProviderConnection(cpr, r); + conn.startAssociationIfNeeded(); if (stable) { conn.stableCount = 1; conn.numStableIncs = 1; @@ -9047,10 +9033,10 @@ public class ActivityManagerService extends IActivityManager.Stub cpr.connections.add(conn); r.conProviders.add(conn); startAssociationLocked(r.uid, r.processName, r.curProcState, - cpr.uid, cpr.name, cpr.info.processName); + cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); return conn; } - cpr.addExternalProcessHandleLocked(externalProcessToken); + cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag); return null; } @@ -9069,6 +9055,7 @@ public class ActivityManagerService extends IActivityManager.Stub conn.unstableCount--; } if (conn.stableCount == 0 && conn.unstableCount == 0) { + conn.stopAssociation(); cpr.connections.remove(conn); conn.client.conProviders.remove(conn); if (conn.client.setProcState < PROCESS_STATE_LAST_ACTIVITY) { @@ -9079,7 +9066,8 @@ public class ActivityManagerService extends IActivityManager.Stub cpr.proc.lastProviderTime = SystemClock.uptimeMillis(); } } - stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name); + stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, + cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); return true; } return false; @@ -9125,7 +9113,8 @@ public class ActivityManagerService extends IActivityManager.Stub } private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, - String name, IBinder token, boolean stable, int userId) { + String name, IBinder token, int callingUid, String callingTag, boolean stable, + int userId) { ContentProviderRecord cpr; ContentProviderConnection conn = null; ProviderInfo cpi = null; @@ -9218,7 +9207,7 @@ public class ActivityManagerService extends IActivityManager.Stub // In this case the provider instance already exists, so we can // return it right away. - conn = incProviderCountLocked(r, cpr, token, stable); + conn = incProviderCountLocked(r, cpr, token, callingUid, callingTag, stable); if (conn != null && (conn.stableCount+conn.unstableCount) == 1) { if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { // If this is a perceptible app accessing the provider, @@ -9462,7 +9451,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mProviderMap.putProviderByName(name, cpr); - conn = incProviderCountLocked(r, cpr, token, stable); + conn = incProviderCountLocked(r, cpr, token, callingUid, callingTag, stable); if (conn != null) { conn.waiting = true; } @@ -9573,21 +9562,23 @@ public class ActivityManagerService extends IActivityManager.Stub } // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal // with cross-user grant. - return getContentProviderImpl(caller, name, null, stable, userId); + return getContentProviderImpl(caller, name, null, Binder.getCallingUid(), null, stable, + userId); } public ContentProviderHolder getContentProviderExternal( - String name, int userId, IBinder token) { + String name, int userId, IBinder token, String tag) { enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, "Do not have permission in call getContentProviderExternal()"); userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "getContentProvider", null); - return getContentProviderExternalUnchecked(name, token, userId); + return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(), + tag != null ? tag : "*external*", userId); } private ContentProviderHolder getContentProviderExternalUnchecked(String name, - IBinder token, int userId) { - return getContentProviderImpl(null, name, token, true, userId); + IBinder token, int callingUid, String callingTag, int userId) { + return getContentProviderImpl(null, name, token, callingUid, callingTag, true, userId); } /** @@ -9709,7 +9700,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized (dst) { dst.provider = src.provider; - dst.proc = r; + dst.setProcess(r); dst.notifyAll(); } updateOomAdjLocked(r, true); @@ -9979,7 +9970,8 @@ public class ActivityManagerService extends IActivityManager.Stub } ContentProviderHolder holder = null; try { - holder = getContentProviderExternalUnchecked(name, null, userId); + holder = getContentProviderExternalUnchecked(name, null, callingUid, + "*getmimetype*", userId); if (holder != null) { return holder.provider.getType(uri); } @@ -10194,7 +10186,8 @@ public class ActivityManagerService extends IActivityManager.Stub final int userId = UserHandle.getCallingUserId(); final Uri uri = Uri.parse(uriString); String name = uri.getAuthority(); - ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null, userId); + ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null, + Binder.getCallingUid(), "*opencontent*", userId); ParcelFileDescriptor pfd = null; if (cph != null) { // We record the binder invoker's uid in thread-local storage before @@ -12763,12 +12756,13 @@ public class ActivityManagerService extends IActivityManager.Stub final File[] files = new File(ANR_TRACE_DIR).listFiles(); if (ArrayUtils.isEmpty(files)) { + pw.println(" <no ANR has occurred since boot>"); return; } // Find the latest file. File latest = null; for (File f : files) { - if (latest == null || latest.getName().compareTo(f.getName()) < 0) { + if ((latest == null) || (latest.lastModified() < f.lastModified())) { latest = f; } } @@ -16341,7 +16335,8 @@ public class ActivityManagerService extends IActivityManager.Stub // clean up this connection, we'll just remove it. cpr.connections.remove(i); if (conn.client.conProviders.remove(conn)) { - stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name); + stopAssociationLocked(capp.uid, capp.processName, cpr.uid, + cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName); } } } @@ -16417,7 +16412,7 @@ public class ActivityManagerService extends IActivityManager.Stub } cpr.provider = null; - cpr.proc = null; + cpr.setProcess(null); } app.pubProviders.clear(); @@ -16432,7 +16427,8 @@ public class ActivityManagerService extends IActivityManager.Stub ContentProviderConnection conn = app.conProviders.get(i); conn.provider.connections.remove(conn); stopAssociationLocked(app.uid, app.processName, conn.provider.uid, - conn.provider.name); + conn.provider.appInfo.longVersionCode, conn.provider.name, + conn.provider.info.processName); } app.conProviders.clear(); } @@ -18504,6 +18500,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Can't call out of the system process with a lock held, so post a message. if (app.instr.mUiAutomationConnection != null) { + mAppOpsService.setAppOpsServiceDelegate(null); + getPackageManagerInternalLocked().setCheckPermissionDelegate(null); mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG, app.instr.mUiAutomationConnection).sendToTarget(); } @@ -18652,7 +18650,8 @@ public class ActivityManagerService extends IActivityManager.Stub } Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState, - int targetUid, ComponentName targetComponent, String targetProcess) { + int targetUid, long targetVersionCode, ComponentName targetComponent, + String targetProcess) { if (!mTrackingAssociations) { return null; } @@ -18688,7 +18687,7 @@ public class ActivityManagerService extends IActivityManager.Stub } void stopAssociationLocked(int sourceUid, String sourceProcess, int targetUid, - ComponentName targetComponent) { + long targetVersionCode, ComponentName targetComponent, String targetProcess) { if (!mTrackingAssociations) { return; } @@ -18748,6 +18747,129 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private final ComputeOomAdjWindowCallback mTmpComputeOomAdjWindowCallback = + new ComputeOomAdjWindowCallback(); + + private final class ComputeOomAdjWindowCallback + implements WindowProcessController.ComputeOomAdjCallback { + + ProcessRecord app; + int adj; + boolean foregroundActivities; + int procState; + int schedGroup; + int appUid; + int logUid; + int processStateCurTop; + + void initialize(ProcessRecord app, int adj, boolean foregroundActivities, + int procState, int schedGroup, int appUid, int logUid, int processStateCurTop) { + this.app = app; + this.adj = adj; + this.foregroundActivities = foregroundActivities; + this.procState = procState; + this.schedGroup = schedGroup; + this.appUid = appUid; + this.logUid = logUid; + this.processStateCurTop = processStateCurTop; + } + + @Override + public void onVisibleActivity() { + // App has a visible activity; only upgrade adjustment. + if (adj > ProcessList.VISIBLE_APP_ADJ) { + adj = ProcessList.VISIBLE_APP_ADJ; + app.adjType = "vis-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to vis-activity: " + app); + } + } + if (procState > processStateCurTop) { + procState = processStateCurTop; + app.adjType = "vis-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise procstate to vis-activity (top): " + app); + } + } + if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; + } + app.cached = false; + app.empty = false; + foregroundActivities = true; + } + + @Override + public void onPausedActivity() { + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + app.adjType = "pause-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to pause-activity: " + app); + } + } + if (procState > processStateCurTop) { + procState = processStateCurTop; + app.adjType = "pause-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise procstate to pause-activity (top): " + app); + } + } + if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; + } + app.cached = false; + app.empty = false; + foregroundActivities = true; + } + + @Override + public void onStoppingActivity(boolean finishing) { + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) { + adj = ProcessList.PERCEPTIBLE_APP_ADJ; + app.adjType = "stop-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise adj to stop-activity: " + app); + } + } + + // For the process state, we will at this point consider the process to be cached. It + // will be cached either as an activity or empty depending on whether the activity is + // finishing. We do this so that we can treat the process as cached for purposes of + // memory trimming (determining current memory level, trim command to send to process) + // since there can be an arbitrary number of stopping processes and they should soon all + // go into the cached state. + if (!finishing) { + if (procState > PROCESS_STATE_LAST_ACTIVITY) { + procState = PROCESS_STATE_LAST_ACTIVITY; + app.adjType = "stop-activity"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise procstate to stop-activity: " + app); + } + } + } + app.cached = false; + app.empty = false; + foregroundActivities = true; + } + + @Override + public void onOtherActivity() { + if (procState > PROCESS_STATE_CACHED_ACTIVITY) { + procState = PROCESS_STATE_CACHED_ACTIVITY; + app.adjType = "cch-act"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, + "Raise procstate to cached activity: " + app); + } + } + } + } + private final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP, boolean doingAll, long now) { if (mAdjSeq == app.adjSeq) { @@ -18919,119 +19041,15 @@ public class ActivityManagerService extends IActivityManager.Stub // Examine all activities if not already foreground. if (!foregroundActivities && wpc.hasActivities()) { - final int[] adjHolder = new int[1]; - adjHolder[0] = adj; - final boolean[] foregroundActivitiesHolder = new boolean[1]; - foregroundActivitiesHolder[0] = foregroundActivities; - int[] procStateHolder = new int[1]; - procStateHolder[0] = procState; - int[] schedGroupHolder = new int[1]; - schedGroupHolder[0] = schedGroup; - - int minLayer = wpc.computeOomAdjFromActivities(ProcessList.VISIBLE_APP_LAYER_MAX, - new WindowProcessController.ComputeOomAdjCallback() { - @Override - public void onVisibleActivity() { - // App has a visible activity; only upgrade adjustment. - if (adjHolder[0] > ProcessList.VISIBLE_APP_ADJ) { - adjHolder[0] = ProcessList.VISIBLE_APP_ADJ; - app.adjType = "vis-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise adj to vis-activity: " + app); - } - } - if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) { - procStateHolder[0] = PROCESS_STATE_CUR_TOP; - app.adjType = "vis-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise procstate to vis-activity (top): " + app); - } - } - if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT; - } - app.cached = false; - app.empty = false; - foregroundActivitiesHolder[0] = true; - } - - @Override - public void onPausedActivity() { - if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) { - adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "pause-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise adj to pause-activity: " + app); - } - } - if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) { - procStateHolder[0] = PROCESS_STATE_CUR_TOP; - app.adjType = "pause-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise procstate to pause-activity (top): " + app); - } - } - if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT; - } - app.cached = false; - app.empty = false; - foregroundActivitiesHolder[0] = true; - } - - @Override - public void onStoppingActivity(boolean finishing) { - if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) { - adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ; - app.adjType = "stop-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise adj to stop-activity: " + app); - } - } - // For the process state, we will at this point consider the process to - // be cached. It will be cached either as an activity or empty depending - // on whether the activity is finishing. We do this so that we can treat - // the process as cached for purposes of memory trimming (determining - // current memory level, trim command to send to process) since there - // can be an arbitrary number of stopping processes and they should soon - // all go into the cached state. - if (!finishing) { - if (procStateHolder[0] > PROCESS_STATE_LAST_ACTIVITY) { - procStateHolder[0] = PROCESS_STATE_LAST_ACTIVITY; - app.adjType = "stop-activity"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise procstate to stop-activity: " + app); - } - } - } - app.cached = false; - app.empty = false; - foregroundActivitiesHolder[0] = true; - } - - @Override - public void onOtherActivity() { - if (procStateHolder[0] > PROCESS_STATE_CACHED_ACTIVITY) { - procStateHolder[0] = PROCESS_STATE_CACHED_ACTIVITY; - app.adjType = "cch-act"; - if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { - reportOomAdjMessageLocked(TAG_OOM_ADJ, - "Raise procstate to cached activity: " + app); - } - } - } - }); + mTmpComputeOomAdjWindowCallback.initialize(app, adj, foregroundActivities, procState, + schedGroup, appUid, logUid, PROCESS_STATE_CUR_TOP); + final int minLayer = wpc.computeOomAdjFromActivities( + ProcessList.VISIBLE_APP_LAYER_MAX, mTmpComputeOomAdjWindowCallback); - adj = adjHolder[0]; - foregroundActivities = foregroundActivitiesHolder[0]; - procState = procStateHolder[0]; - schedGroup = schedGroupHolder[0]; + adj = mTmpComputeOomAdjWindowCallback.adj; + foregroundActivities = mTmpComputeOomAdjWindowCallback.foregroundActivities; + procState = mTmpComputeOomAdjWindowCallback.procState; + schedGroup = mTmpComputeOomAdjWindowCallback.schedGroup; if (adj == ProcessList.VISIBLE_APP_ADJ) { adj += minLayer; @@ -19254,10 +19272,11 @@ public class ActivityManagerService extends IActivityManager.Stub // all connected clients. ConnectionRecord cr = clist.get(i); if (cr.binding.client == app) { - // Binding to ourself is not interesting. + // Binding to oneself is not interesting. continue; } + boolean trackedProcState = false; if ((cr.flags&Context.BIND_WAIVE_PRIORITY) == 0) { ProcessRecord client = cr.binding.client; computeOomAdjLocked(client, cachedAdj, TOP_APP, doingAll, now); @@ -19329,6 +19348,8 @@ public class ActivityManagerService extends IActivityManager.Stub newAdj = ProcessList.PERSISTENT_SERVICE_ADJ; schedGroup = ProcessList.SCHED_GROUP_DEFAULT; procState = ActivityManager.PROCESS_STATE_PERSISTENT; + cr.trackProcState(procState, mAdjSeq, now); + trackedProcState = true; } } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ @@ -19414,6 +19435,9 @@ public class ActivityManagerService extends IActivityManager.Stub ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; } } + if (!trackedProcState) { + cr.trackProcState(clientProcState, mAdjSeq, now); + } if (procState > clientProcState) { procState = clientProcState; if (adjType == null) { @@ -19543,6 +19567,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + conn.trackProcState(clientProcState, mAdjSeq, now); if (procState > clientProcState) { procState = clientProcState; } @@ -20812,6 +20837,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + for (int i=N-1; i>=0; i--) { ProcessRecord app = mLruProcesses.get(i); if (!app.killedByAm && app.thread != null) { @@ -20875,6 +20901,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } + mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now); + incrementProcStateSeqAndNotifyAppsLocked(); mNumServiceProcs = mNewNumServiceProcs; @@ -22305,9 +22333,8 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public boolean isUserRunning(int userId, int flags) { - synchronized (ActivityManagerService.this) { - return mUserController.isUserRunning(userId, flags); - } + // Holding am lock isn't required to call into user controller. + return mUserController.isUserRunning(userId, flags); } @Override @@ -22378,6 +22405,41 @@ public class ActivityManagerService extends IActivityManager.Stub public void sendForegroundProfileChanged(int userId) { mUserController.sendForegroundProfileChanged(userId); } + + @Override + public boolean shouldConfirmCredentials(int userId) { + return mUserController.shouldConfirmCredentials(userId); + } + + @Override + public int[] getCurrentProfileIds() { + return mUserController.getCurrentProfileIds(); + } + + @Override + public UserInfo getCurrentUser() { + return mUserController.getCurrentUser(); + } + + @Override + public void ensureNotSpecialUser(int userId) { + mUserController.ensureNotSpecialUser(userId); + } + + @Override + public boolean isCurrentProfile(int userId) { + return mUserController.isCurrentProfile(userId); + } + + @Override + public boolean hasStartedUserState(int userId) { + return mUserController.hasStartedUserState(userId); + } + + @Override + public void finishUserSwitch(Object uss) { + mUserController.finishUserSwitch((UserState) uss); + } } /** @@ -22628,4 +22690,143 @@ public class ActivityManagerService extends IActivityManager.Stub return mNmi != null; } } + + @Override + public void startDelegateShellPermissionIdentity(int delegateUid) { + if (UserHandle.getCallingAppId() != Process.SHELL_UID + && UserHandle.getCallingAppId() != Process.ROOT_UID) { + throw new SecurityException("Only the shell can delegate its permissions"); + } + + // We allow delegation only to one instrumentation started from the shell + synchronized (ActivityManagerService.this) { + // If there is a delegate it should be the same instance for app ops and permissions. + if (mAppOpsService.getAppOpsServiceDelegate() + != getPackageManagerInternalLocked().getCheckPermissionDelegate()) { + throw new IllegalStateException("Bad shell delegate state"); + } + + // If the delegate is already set up for the target UID, nothing to do. + if (mAppOpsService.getAppOpsServiceDelegate() != null) { + if (!(mAppOpsService.getAppOpsServiceDelegate() instanceof ShellDelegate)) { + throw new IllegalStateException("Bad shell delegate state"); + } + if (((ShellDelegate) mAppOpsService.getAppOpsServiceDelegate()) + .getDelegateUid() != delegateUid) { + throw new SecurityException("Shell can delegate permissions only " + + "to one instrumentation at a time"); + } + return; + } + + final int instrCount = mActiveInstrumentation.size(); + for (int i = 0; i < instrCount; i++) { + final ActiveInstrumentation instr = mActiveInstrumentation.get(i); + if (instr.mTargetInfo.uid != delegateUid) { + continue; + } + // If instrumentation started from the shell the connection is not null + if (instr.mUiAutomationConnection == null) { + throw new SecurityException("Shell can delegate its permissions" + + " only to an instrumentation started from the shell"); + } + + // Hook them up... + final ShellDelegate shellDelegate = new ShellDelegate( + instr.mTargetInfo.packageName, delegateUid); + mAppOpsService.setAppOpsServiceDelegate(shellDelegate); + getPackageManagerInternalLocked().setCheckPermissionDelegate(shellDelegate); + return; + } + } + } + + @Override + public void stopDelegateShellPermissionIdentity() { + if (UserHandle.getCallingAppId() != Process.SHELL_UID + && UserHandle.getCallingAppId() != Process.ROOT_UID) { + throw new SecurityException("Only the shell can delegate its permissions"); + } + synchronized (ActivityManagerService.this) { + mAppOpsService.setAppOpsServiceDelegate(null); + getPackageManagerInternalLocked().setCheckPermissionDelegate(null); + } + } + + private class ShellDelegate implements CheckOpsDelegate, CheckPermissionDelegate { + private final String mTargetPackageName; + private final int mTargetUid; + + ShellDelegate(String targetPacakgeName, int targetUid) { + mTargetPackageName = targetPacakgeName; + mTargetUid = targetUid; + } + + int getDelegateUid() { + return mTargetUid; + } + + @Override + public int checkOperation(int code, int uid, String packageName, + TriFunction<Integer, Integer, String, Integer> superImpl) { + if (uid == mTargetUid) { + final long identity = Binder.clearCallingIdentity(); + try { + return superImpl.apply(code, Process.SHELL_UID, + "com.android.shell"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return superImpl.apply(code, uid, packageName); + } + + @Override + public int checkAudioOperation(int code, int usage, int uid, String packageName, + QuadFunction<Integer, Integer, Integer, String, Integer> superImpl) { + if (uid == mTargetUid) { + final long identity = Binder.clearCallingIdentity(); + try { + return superImpl.apply(code, usage, Process.SHELL_UID, + "com.android.shell"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return superImpl.apply(code, usage, uid, packageName); + } + + @Override + public int noteOperation(int code, int uid, String packageName, + TriFunction<Integer, Integer, String, Integer> superImpl) { + if (uid == mTargetUid) { + final long identity = Binder.clearCallingIdentity(); + try { + return mAppOpsService.noteProxyOperation(code, Process.SHELL_UID, + "com.android.shell", uid, packageName); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return superImpl.apply(code, uid, packageName); + } + + @Override + public int checkPermission(String permName, String pkgName, int userId, + TriFunction<String, String, Integer, Integer> superImpl) { + if (mTargetPackageName.equals(pkgName)) { + return superImpl.apply(permName, "com.android.shell", userId); + } + return superImpl.apply(permName, pkgName, userId); + } + + @Override + public int checkUidPermission(String permName, int uid, + BiFunction<String, Integer, Integer> superImpl) { + if (uid == mTargetUid) { + return superImpl.apply(permName, Process.SHELL_UID); + } + return superImpl.apply(permName, uid); + } + } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index b44ce9aeea33..70f638df6f33 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1877,7 +1877,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // TODO: To be more accurate, the mark should be before the onCreate, // not after the onResume. But for subsequent starts, onResume is fine. if (hasProcess()) { - cpuTimeAtResume = service.mAm.mProcessCpuTracker.getCpuTimeForPid(app.getPid()); + cpuTimeAtResume = app.getCpuTime(); } else { cpuTimeAtResume = 0; // Couldn't get the cpu time of process } @@ -2186,7 +2186,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0 || (mStackSupervisor.isCurrentProfileLocked(userId) - && service.mAm.mUserController.isUserRunning(userId, 0 /* flags */)); + && service.mAmInternal.isUserRunning(userId, 0 /* flags */)); } /** diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index c76df8bef866..b0f1c45327cf 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -457,7 +457,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mHandler = new ActivityStackHandler(supervisor.mLooper); mWindowManager = mService.mWindowManager; mStackId = stackId; - mCurrentUser = mService.mAm.mUserController.getCurrentUserId(); + mCurrentUser = mService.mAmInternal.getCurrentUserId(); mTmpRect2.setEmpty(); // Set display id before setting activity and window type to make sure it won't affect // stacks on a wrong display. @@ -1622,8 +1622,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (prev.hasProcess() && prev.cpuTimeAtResume > 0 && mService.mAm.mBatteryStatsService.isOnBattery()) { - long diff = mService.mAm.mProcessCpuTracker.getCpuTimeForPid(prev.app.getPid()) - - prev.cpuTimeAtResume; + long diff = prev.app.getCpuTime() - prev.cpuTimeAtResume; if (diff > 0) { BatteryStatsImpl bsi = mService.mAm.mBatteryStatsService.getActiveStatistics(); synchronized (bsi) { @@ -2398,7 +2397,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai // Make sure that the user who owns this activity is started. If not, // we will just leave it as is because someone should be bringing // another user's activities to the top of the stack. - if (!mService.mAm.mUserController.hasStartedUserState(next.userId)) { + if (!mService.mAmInternal.hasStartedUserState(next.userId)) { Slog.w(TAG, "Skipping resume of top activity " + next + ": user " + next.userId + " is stopped"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 7f749b38773e..e3e1c48bb1c1 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2112,12 +2112,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Complete user switch if (startingUsers != null) { for (int i = 0; i < startingUsers.size(); i++) { - mService.mAm.mUserController.finishUserSwitch(startingUsers.get(i)); + mService.mAmInternal.finishUserSwitch(startingUsers.get(i)); } } } - mService.mAm.trimApplications(); + mService.mAmInternal.trimApplications(); //dump(); //mWindowManager.dump(); @@ -3837,7 +3837,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** Checks whether the userid is a profile of the current user. */ boolean isCurrentProfileLocked(int userId) { if (userId == mCurrentUser) return true; - return mService.mAm.mUserController.isCurrentProfile(userId); + return mService.mAmInternal.isCurrentProfile(userId); } /** @@ -4789,7 +4789,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // If the user must confirm credentials (e.g. when first launching a work app and the // Work Challenge is present) let startActivityInPackage handle the intercepting. - if (!mService.mAm.mUserController.shouldConfirmCredentials(task.userId) + if (!mService.mAmInternal.shouldConfirmCredentials(task.userId) && task.getRootActivity() != null) { final ActivityRecord targetActivity = task.getTopActivity(); diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index f7ea4b228e52..110767174e5c 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -240,7 +240,7 @@ public class ActivityStartController { return mService.handleIncomingUser( realCallingPid, realCallingUid, targetUserId, reason); } else { - mService.mAm.mUserController.ensureNotSpecialUser(targetUserId); + mService.mAmInternal.ensureNotSpecialUser(targetUserId); return targetUserId; } } diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 171c0bbd1812..ca12716e7199 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -69,7 +69,6 @@ class ActivityStartInterceptor { private final ActivityTaskManagerService mService; private final ActivityStackSupervisor mSupervisor; private final Context mServiceContext; - private final UserController mUserController; // UserManager cannot be final as it's not ready when this class is instantiated during boot private UserManager mUserManager; @@ -101,16 +100,15 @@ class ActivityStartInterceptor { ActivityStartInterceptor( ActivityTaskManagerService service, ActivityStackSupervisor supervisor) { - this(service, supervisor, service.mContext, service.mAm.mUserController); + this(service, supervisor, service.mContext); } @VisibleForTesting ActivityStartInterceptor(ActivityTaskManagerService service, ActivityStackSupervisor supervisor, - Context context, UserController userController) { + Context context) { mService = service; mSupervisor = supervisor; mServiceContext = context; - mUserController = userController; } /** @@ -298,7 +296,7 @@ class ActivityStartInterceptor { * @return The intercepting intent if needed. */ private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) { - if (!mUserController.shouldConfirmCredentials(userId)) { + if (!mService.mAmInternal.shouldConfirmCredentials(userId)) { return null; } // TODO(b/28935539): should allow certain activities to bypass work challenge diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 50d0212888fe..3ed2875c7377 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -4547,9 +4547,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mShowDialogs && !mSleeping && !mShuttingDown && !mKeyguardController.isKeyguardOrAodShowing(DEFAULT_DISPLAY) && !hasUserRestriction(UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, - mAm.mUserController.getCurrentUserId()) + mAmInternal.getCurrentUserId()) && !(UserManager.isDeviceInDemoMode(mContext) - && mAm.mUserController.getCurrentUser().isDemo()); + && mAmInternal.getCurrentUser().isDemo()); } /** diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index 679024ee4c94..2cea4faba613 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -16,12 +16,18 @@ package com.android.server.am; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; + import android.app.IServiceConnection; import android.app.PendingIntent; import android.content.Context; +import android.util.Slog; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; +import com.android.internal.app.procstats.AssociationState; +import com.android.internal.app.procstats.ProcessStats; + import java.io.PrintWriter; /** @@ -34,6 +40,9 @@ final class ConnectionRecord { final int flags; // Binding options. final int clientLabel; // String resource labeling this client. final PendingIntent clientIntent; // How to launch the client. + final int clientUid; // The identity of this connection's client + final String clientProcessName; // The source process of this connection's client + public AssociationState.SourceState association; // Association tracking String stringName; // Caching of toString. boolean serviceDead; // Well is it? @@ -83,14 +92,52 @@ final class ConnectionRecord { } ConnectionRecord(AppBindRecord _binding, ActivityRecord _activity, - IServiceConnection _conn, int _flags, - int _clientLabel, PendingIntent _clientIntent) { + IServiceConnection _conn, int _flags, + int _clientLabel, PendingIntent _clientIntent, + int _clientUid, String _clientProcessName) { binding = _binding; activity = _activity; conn = _conn; flags = _flags; clientLabel = _clientLabel; clientIntent = _clientIntent; + clientUid = _clientUid; + clientProcessName = _clientProcessName; + } + + public void startAssociationIfNeeded() { + // If we don't already have an active association, create one... but only if this + // is an association between two different processes. + if (association == null && (binding.service.appInfo.uid != clientUid + || !binding.service.processName.equals(clientProcessName))) { + ProcessStats.ProcessStateHolder holder = binding.service.app != null + ? binding.service.app.pkgList.get(binding.service.name.getPackageName()) : null; + if (holder == null) { + Slog.wtf(TAG_AM, "No package in referenced service " + + binding.service.name.toShortString() + ": proc=" + binding.service.app); + } else if (holder.pkg == null) { + Slog.wtf(TAG_AM, "Inactive holder in referenced service " + + binding.service.name.toShortString() + ": proc=" + binding.service.app); + } else { + association = holder.pkg.getAssociationStateLocked(holder.state, + binding.service.name.getClassName()).startSource(clientUid, + clientProcessName); + + } + } + } + + public void trackProcState(int procState, int seq, long now) { + if (association != null) { + association.trackProcState(procState, seq, now); + } + } + + public void stopAssociation() { + if (association != null) { + association.stop(); + association = null; + } } public String toString() { diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java index f2c9e2fd2297..36d3f4f619de 100644 --- a/services/core/java/com/android/server/am/ContentProviderConnection.java +++ b/services/core/java/com/android/server/am/ContentProviderConnection.java @@ -18,14 +18,21 @@ package com.android.server.am; import android.os.Binder; import android.os.SystemClock; +import android.util.Slog; import android.util.TimeUtils; +import com.android.internal.app.procstats.AssociationState; +import com.android.internal.app.procstats.ProcessStats; + +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; + /** * Represents a link between a content provider and client. */ public final class ContentProviderConnection extends Binder { public final ContentProviderRecord provider; public final ProcessRecord client; + public AssociationState.SourceState association; public final long createTime; public int stableCount; public int unstableCount; @@ -45,6 +52,40 @@ public final class ContentProviderConnection extends Binder { createTime = SystemClock.elapsedRealtime(); } + public void startAssociationIfNeeded() { + // If we don't already have an active association, create one... but only if this + // is an association between two different processes. + if (association == null && (provider.appInfo.uid != client.uid + || !provider.info.processName.equals(client.processName))) { + ProcessStats.ProcessStateHolder holder = provider.proc != null + ? provider.proc.pkgList.get(provider.name.getPackageName()) : null; + if (holder == null) { + Slog.wtf(TAG_AM, "No package in referenced provider " + + provider.name.toShortString() + ": proc=" + provider.proc); + } else if (holder.pkg == null) { + Slog.wtf(TAG_AM, "Inactive holder in referenced provider " + + provider.name.toShortString() + ": proc=" + provider.proc); + } else { + association = holder.pkg.getAssociationStateLocked(holder.state, + provider.name.getClassName()).startSource(client.uid, client.processName); + + } + } + } + + public void trackProcState(int procState, int seq, long now) { + if (association != null) { + association.trackProcState(procState, seq, now); + } + } + + public void stopAssociation() { + if (association != null) { + association.stop(); + association = null; + } + } + public String toString() { StringBuilder sb = new StringBuilder(128); sb.append("ContentProviderConnection{"); diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java index cd39bcd03d36..53783bebe7f1 100644 --- a/services/core/java/com/android/server/am/ContentProviderRecord.java +++ b/services/core/java/com/android/server/am/ContentProviderRecord.java @@ -16,6 +16,8 @@ package com.android.server.am; +import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; + import android.app.ContentProviderHolder; import android.content.ComponentName; import android.content.IContentProvider; @@ -26,11 +28,14 @@ import android.os.IBinder.DeathRecipient; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.util.ArrayMap; import android.util.Slog; +import com.android.internal.app.procstats.AssociationState; +import com.android.internal.app.procstats.ProcessStats; + import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; final class ContentProviderRecord implements ComponentName.WithComponentName { final ActivityManagerService service; @@ -46,7 +51,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { = new ArrayList<ContentProviderConnection>(); //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); // Handles for non-framework processes supported by this provider - HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; + ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; // Count for external process for which we have no handles. int externalProcessNoHandleCount; ProcessRecord proc; // if non-null, hosting process. @@ -83,22 +88,45 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { return holder; } + public void setProcess(ProcessRecord proc) { + this.proc = proc; + for (int iconn = connections.size() - 1; iconn >= 0; iconn--) { + final ContentProviderConnection conn = connections.get(iconn); + if (proc != null) { + conn.startAssociationIfNeeded(); + } else { + conn.stopAssociation(); + } + } + if (externalProcessTokenToHandle != null) { + for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) { + final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext); + if (proc != null) { + handle.startAssociationIfNeeded(this); + } else { + handle.stopAssociation(); + } + } + } + } + public boolean canRunHere(ProcessRecord app) { return (info.multiprocess || info.processName.equals(app.processName)) && uid == app.info.uid; } - public void addExternalProcessHandleLocked(IBinder token) { + public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) { if (token == null) { externalProcessNoHandleCount++; } else { if (externalProcessTokenToHandle == null) { - externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>(); + externalProcessTokenToHandle = new ArrayMap<>(); } ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); if (handle == null) { - handle = new ExternalProcessHandle(token); + handle = new ExternalProcessHandle(token, callingUid, callingTag); externalProcessTokenToHandle.put(token, handle); + handle.startAssociationIfNeeded(this); } handle.mAcquisitionCount++; } @@ -129,6 +157,7 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { private void removeExternalProcessHandleInternalLocked(IBinder token) { ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); handle.unlinkFromOwnDeathLocked(); + handle.stopAssociation(); externalProcessTokenToHandle.remove(token); if (externalProcessTokenToHandle.size() == 0) { externalProcessTokenToHandle = null; @@ -234,11 +263,16 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { private class ExternalProcessHandle implements DeathRecipient { private static final String LOG_TAG = "ExternalProcessHanldle"; - private final IBinder mToken; - private int mAcquisitionCount; + final IBinder mToken; + final int mOwningUid; + final String mOwningProcessName; + int mAcquisitionCount; + AssociationState.SourceState mAssociation; - public ExternalProcessHandle(IBinder token) { + public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) { mToken = token; + mOwningUid = owningUid; + mOwningProcessName = owningProcessName; try { token.linkToDeath(this, 0); } catch (RemoteException re) { @@ -250,6 +284,35 @@ final class ContentProviderRecord implements ComponentName.WithComponentName { mToken.unlinkToDeath(this, 0); } + public void startAssociationIfNeeded(ContentProviderRecord provider) { + // If we don't already have an active association, create one... but only if this + // is an association between two different processes. + if (mAssociation == null && (provider.appInfo.uid != mOwningUid + || !provider.info.processName.equals(mOwningProcessName))) { + ProcessStats.ProcessStateHolder holder = provider.proc != null + ? provider.proc.pkgList.get(provider.name.getPackageName()) : null; + if (holder == null) { + Slog.wtf(TAG_AM, "No package in referenced provider " + + provider.name.toShortString() + ": proc=" + provider.proc); + } else if (holder.pkg == null) { + Slog.wtf(TAG_AM, "Inactive holder in referenced provider " + + provider.name.toShortString() + ": proc=" + provider.proc); + } else { + mAssociation = holder.pkg.getAssociationStateLocked(holder.state, + provider.name.getClassName()).startSource(mOwningUid, + mOwningProcessName); + + } + } + } + + public void stopAssociation() { + if (mAssociation != null) { + mAssociation.stop(); + mAssociation = null; + } + } + @Override public void binderDied() { synchronized (service) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 5a44ab6a37fb..ea6d134ddfde 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -91,6 +91,10 @@ final class ProcessRecord implements WindowProcessListener { return mPkgList.valueAt(index); } + ProcessStats.ProcessStateHolder get(String pkgName) { + return mPkgList.get(pkgName); + } + boolean containsKey(Object key) { return mPkgList.containsKey(key); } @@ -546,7 +550,7 @@ final class ProcessRecord implements WindowProcessListener { if (holder.state != null && holder.state != origBase) { holder.state.makeInactive(); } - holder.state = tracker.getProcessStateLocked(pkgList.keyAt(i), uid, + tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), uid, info.longVersionCode, processName); if (holder.state != baseProcessTracker) { holder.state.makeActive(); @@ -573,6 +577,7 @@ final class ProcessRecord implements WindowProcessListener { if (holder.state != null && holder.state != origBase) { holder.state.makeInactive(); } + holder.pkg = null; holder.state = null; } } @@ -801,8 +806,7 @@ final class ProcessRecord implements WindowProcessListener { ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( versionCode); if (baseProcessTracker != null) { - holder.state = tracker.getProcessStateLocked( - pkg, uid, versionCode, processName); + tracker.updateProcessStateHolderLocked(holder, pkg, uid, versionCode, processName); pkgList.put(pkg, holder); if (holder.state != baseProcessTracker) { holder.state.makeActive(); @@ -848,14 +852,13 @@ final class ProcessRecord implements WindowProcessListener { } pkgList.clear(); - ProcessState ps = tracker.getProcessStateLocked( - info.packageName, uid, info.longVersionCode, processName); ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( info.longVersionCode); - holder.state = ps; + tracker.updateProcessStateHolderLocked(holder, info.packageName, uid, + info.longVersionCode, processName); pkgList.put(info.packageName, holder); - if (ps != baseProcessTracker) { - ps.makeActive(); + if (holder.state != baseProcessTracker) { + holder.state.makeActive(); } } } else if (N != 1) { @@ -999,4 +1002,11 @@ final class ProcessRecord implements WindowProcessListener { } } + /** + * Returns the total time (in milliseconds) spent executing in both user and system code. + * Safe to call without lock held. + */ + public long getCpuTime() { + return mService.mProcessCpuTracker.getCpuTimeForPid(pid); + } } diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index c10d81b96cbc..f0bd8fa31478 100644 --- a/services/core/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java @@ -16,14 +16,12 @@ package com.android.server.am; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; -import android.service.procstats.ProcessStatsProto; import android.service.procstats.ProcessStatsServiceDumpProto; import android.util.ArrayMap; import android.util.AtomicFile; @@ -120,11 +118,20 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } + @GuardedBy("mAm") + public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder, + String packageName, int uid, long versionCode, String processName) { + holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode); + holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName); + } + + @GuardedBy("mAm") public ProcessState getProcessStateLocked(String packageName, int uid, long versionCode, String processName) { return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName); } + @GuardedBy("mAm") public ServiceState getServiceStateLocked(String packageName, int uid, long versionCode, String processName, String className) { return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName, @@ -174,15 +181,23 @@ public final class ProcessStatsService extends IProcessStats.Stub { return false; } + @GuardedBy("mAm") public int getMemFactorLocked() { return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0; } + @GuardedBy("mAm") public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem, long nativeMem) { mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem); } + @GuardedBy("mAm") + public void updateTrackingAssociationsLocked(int curSeq, long now) { + mProcessStats.updateTrackingAssociationsLocked(curSeq, now); + } + + @GuardedBy("mAm") public boolean shouldWriteNowLocked(long now) { if (now > (mLastWriteTime+WRITE_PERIOD)) { if (SystemClock.elapsedRealtime() @@ -196,6 +211,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { return false; } + @GuardedBy("mAm") public void shutdownLocked() { Slog.w(TAG, "Writing process stats before shutdown..."); mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN; @@ -203,14 +219,17 @@ public final class ProcessStatsService extends IProcessStats.Stub { mShuttingDown = true; } + @GuardedBy("mAm") public void writeStateAsyncLocked() { writeStateLocked(false); } + @GuardedBy("mAm") public void writeStateSyncLocked() { writeStateLocked(true); } + @GuardedBy("mAm") private void writeStateLocked(boolean sync) { if (mShuttingDown) { return; @@ -220,6 +239,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { writeStateLocked(sync, commitPending); } + @GuardedBy("mAm") public void writeStateLocked(boolean sync, final boolean commit) { final long totalTime; synchronized (mPendingWriteLock) { @@ -298,6 +318,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } + @GuardedBy("mAm") boolean readLocked(ProcessStats stats, AtomicFile file) { try { FileInputStream stream = file.openRead(); @@ -342,6 +363,13 @@ public final class ProcessStatsService extends IProcessStats.Stub { + ": " + pkgState.mServices.valueAt(isvc)); } + final int NASCS = pkgState.mAssociations.size(); + for (int iasc=0; iasc<NASCS; iasc++) { + Slog.w(TAG, " Association " + + pkgState.mServices.keyAt(iasc) + + ": " + pkgState.mAssociations.valueAt(iasc)); + + } } } } @@ -383,6 +411,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { return filesArray; } + @GuardedBy("mAm") public void trimHistoricStatesWriteLocked() { ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true); if (filesArray == null) { @@ -395,6 +424,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } + @GuardedBy("mAm") boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now, String reqPackage) { diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index 749589b970b3..1967c76b23e3 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -78,6 +78,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -140,7 +141,6 @@ class RecentTasks { private final TaskPersister mTaskPersister; private final ActivityTaskManagerService mService; private final ActivityStackSupervisor mSupervisor; - private final UserController mUserController; /** * Keeps track of the static recents package/component which is granted additional permissions @@ -181,11 +181,9 @@ class RecentTasks { private final TaskActivitiesReport mTmpReport = new TaskActivitiesReport(); @VisibleForTesting - RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister, - UserController userController) { + RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { mService = service; mSupervisor = mService.mStackSupervisor; - mUserController = userController; mTaskPersister = taskPersister; mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic(); mHasVisibleRecentTasks = true; @@ -196,7 +194,6 @@ class RecentTasks { final Resources res = service.mContext.getResources(); mService = service; mSupervisor = mService.mStackSupervisor; - mUserController = service.mAm.mUserController; mTaskPersister = new TaskPersister(systemDir, stackSupervisor, service, this); mGlobalMaxNumTasks = ActivityTaskManager.getMaxRecentTasksStatic(); mHasVisibleRecentTasks = res.getBoolean(com.android.internal.R.bool.config_hasRecents); @@ -712,6 +709,27 @@ class RecentTasks { return list; } + @VisibleForTesting + Set<Integer> getProfileIds(int userId) { + Set<Integer> userIds = new ArraySet<>(); + final List<UserInfo> profiles = mService.getUserManager().getProfiles(userId, + false /* enabledOnly */); + for (int i = profiles.size() - 1; i >= 0; --i) { + userIds.add(profiles.get(i).id); + } + return userIds; + } + + @VisibleForTesting + UserInfo getUserInfo(int userId) { + return mService.getUserManager().getUserInfo(userId); + } + + @VisibleForTesting + int[] getCurrentProfileIds() { + return mService.mAmInternal.getCurrentProfileIds(); + } + /** * @return the list of recent tasks for presentation. */ @@ -725,7 +743,7 @@ class RecentTasks { } loadUserRecentsLocked(userId); - final Set<Integer> includedUsers = mUserController.getProfileIds(userId); + final Set<Integer> includedUsers = getProfileIds(userId); includedUsers.add(Integer.valueOf(userId)); final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>(); @@ -1040,10 +1058,10 @@ class RecentTasks { } // Remove any tasks that belong to currently quiet profiles - final int[] profileUserIds = mUserController.getCurrentProfileIds(); + final int[] profileUserIds = getCurrentProfileIds(); mTmpQuietProfileUserIds.clear(); for (int userId : profileUserIds) { - final UserInfo userInfo = mUserController.getUserInfo(userId); + final UserInfo userInfo = getUserInfo(userId); if (userInfo != null && userInfo.isManagedProfile() && userInfo.isQuietModeEnabled()) { mTmpQuietProfileUserIds.put(userId, true); } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 4d89d015b669..f72b8010429b 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -500,6 +500,21 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN restartTracker.setRestarting(true, memFactor, now); } + public void setProcess(ProcessRecord _proc) { + app = _proc; + for (int conni=connections.size()-1; conni>=0; conni--) { + ArrayList<ConnectionRecord> cr = connections.valueAt(conni); + for (int i=0; i<cr.size(); i++) { + final ConnectionRecord conn = cr.get(i); + if (_proc != null) { + conn.startAssociationIfNeeded(); + } else { + conn.stopAssociation(); + } + } + } + } + public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) { Intent.FilterComparison filter = new Intent.FilterComparison(intent); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 992179a2637b..fa670a250886 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -259,11 +259,14 @@ class UserController implements Handler.Callback { } void finishUserSwitch(UserState uss) { - finishUserBoot(uss); - startProfiles(); - synchronized (mLock) { - stopRunningUsersLU(mMaxRunningUsers); - } + // This call holds the AM lock so we post to the handler. + mHandler.post(() -> { + finishUserBoot(uss); + startProfiles(); + synchronized (mLock) { + stopRunningUsersLU(mMaxRunningUsers); + } + }); } List<Integer> getRunningUsersLU() { @@ -1573,7 +1576,9 @@ class UserController implements Handler.Callback { } boolean hasStartedUserState(int userId) { - return mStartedUsers.get(userId) != null; + synchronized (mLock) { + return mStartedUsers.get(userId) != null; + } } private void updateStartedUserArrayLU() { @@ -1749,7 +1754,7 @@ class UserController implements Handler.Callback { return ums != null ? ums.getUserIds() : new int[] { 0 }; } - UserInfo getUserInfo(int userId) { + private UserInfo getUserInfo(int userId) { return mInjector.getUserManager().getUserInfo(userId); } @@ -1775,7 +1780,7 @@ class UserController implements Handler.Callback { return mInjector.getUserManager().exists(userId); } - void enforceShellRestriction(String restriction, int userHandle) { + private void enforceShellRestriction(String restriction, int userHandle) { if (Binder.getCallingUid() == SHELL_UID) { if (userHandle < 0 || hasUserRestriction(restriction, userHandle)) { throw new SecurityException("Shell does not have permission to access user " @@ -1788,16 +1793,6 @@ class UserController implements Handler.Callback { return mInjector.getUserManager().hasUserRestriction(restriction, userId); } - Set<Integer> getProfileIds(int userId) { - Set<Integer> userIds = new HashSet<>(); - final List<UserInfo> profiles = mInjector.getUserManager().getProfiles(userId, - false /* enabledOnly */); - for (UserInfo user : profiles) { - userIds.add(user.id); - } - return userIds; - } - boolean isSameProfileGroup(int callingUserId, int targetUserId) { if (callingUserId == targetUserId) { return true; diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java index 64a273efc4ee..817905a5e3d4 100644 --- a/services/core/java/com/android/server/am/WindowProcessController.java +++ b/services/core/java/com/android/server/am/WindowProcessController.java @@ -478,6 +478,11 @@ public class WindowProcessController { mAtm.mH.post(r); } + /** Returns the total time (in milliseconds) spent executing in both user and system code. */ + public long getCpuTime() { + return (mListener != null) ? mListener.getCpuTime() : 0; + } + void addRecentTask(TaskRecord task) { mRecentTasks.add(task); } diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/am/WindowProcessListener.java index 92e4461c4452..2de3e3763028 100644 --- a/services/core/java/com/android/server/am/WindowProcessListener.java +++ b/services/core/java/com/android/server/am/WindowProcessListener.java @@ -44,4 +44,7 @@ public interface WindowProcessListener { /** Set process package been removed from device. */ void setRemoved(boolean removed); + + /** Returns the total time (in milliseconds) spent executing in both user and system code. */ + long getCpuTime(); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6971f718a13c..d1fd0d5ebc5d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -3814,6 +3814,10 @@ public class AudioService extends IAudioService.Stub int delay = checkSendBecomingNoisyIntent( AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState, AudioSystem.DEVICE_NONE); + final String addr = btDevice == null ? "null" : btDevice.getAddress(); + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "A2DP service connected: device addr=" + addr + + " state=" + state)); queueMsgUnderWakeLock(mAudioHandler, MSG_SET_A2DP_SINK_CONNECTION_STATE, state, @@ -4677,7 +4681,14 @@ public class AudioService extends IAudioService.Stub public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent, int a2dpVolume) { + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state + // only querying address as this is the only readily available field on the device + + " addr=" + device.getAddress() + + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent + + " vol=" + a2dpVolume)); if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) { + mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored")); return 0; } return setBluetoothA2dpDeviceConnectionStateInt( @@ -5630,7 +5641,7 @@ public class AudioService extends IAudioService.Stub case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: { WiredDeviceConnectionState connectState = (WiredDeviceConnectionState)msg.obj; - mWiredDevLogger.log(new WiredDevConnectEvent(connectState)); + mDeviceLogger.log(new WiredDevConnectEvent(connectState)); onSetWiredDeviceConnectionState(connectState.mType, connectState.mState, connectState.mAddress, connectState.mName, connectState.mCaller); mAudioEventWakeLock.release(); @@ -6085,10 +6096,14 @@ public class AudioService extends IAudioService.Stub if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "onBluetoothA2dpDeviceConfigChange addr=" + address)); int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; synchronized (mConnectedDevices) { if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) { + mDeviceLogger.log(new AudioEventLogger.StringEvent( + "A2dp config change ignored")); return; } final String key = makeDeviceListKey(device, address); @@ -7185,19 +7200,20 @@ public class AudioService extends IAudioService.Stub //========================================================================================== // AudioService logging and dumpsys //========================================================================================== - final int LOG_NB_EVENTS_PHONE_STATE = 20; - final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30; - final int LOG_NB_EVENTS_FORCE_USE = 20; - final int LOG_NB_EVENTS_VOLUME = 40; - final int LOG_NB_EVENTS_DYN_POLICY = 10; + static final int LOG_NB_EVENTS_PHONE_STATE = 20; + static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30; + static final int LOG_NB_EVENTS_FORCE_USE = 20; + static final int LOG_NB_EVENTS_VOLUME = 40; + static final int LOG_NB_EVENTS_DYN_POLICY = 10; final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE, "phone state (logged after successfull call to AudioSystem.setPhoneState(int))"); - final private AudioEventLogger mWiredDevLogger = new AudioEventLogger( - LOG_NB_EVENTS_WIRED_DEV_CONNECTION, - "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)" - ); + // logs for wired + A2DP device connections: + // - wired: logged before onSetWiredDeviceConnectionState() is executed + // - A2DP: logged at reception of method call + final private AudioEventLogger mDeviceLogger = new AudioEventLogger( + LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection"); final private AudioEventLogger mForceUseLogger = new AudioEventLogger( LOG_NB_EVENTS_FORCE_USE, @@ -7286,7 +7302,7 @@ public class AudioService extends IAudioService.Stub pw.println("\nEvent logs:"); mModeLogger.dump(pw); pw.println("\n"); - mWiredDevLogger.dump(pw); + mDeviceLogger.dump(pw); pw.println("\n"); mForceUseLogger.dump(pw); pw.println("\n"); diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index fbee86a84f85..9e6b659dbf93 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -379,7 +379,7 @@ public class TetherInterfaceStateMachine extends StateMachine { // that adding routes that already exist does not cause an // error (EEXIST is silently ignored). mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded); - } catch (RemoteException e) { + } catch (Exception e) { mLog.e("Failed to add IPv6 routes to local table: " + e); } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index b9a279ad13ea..21ae048e1d75 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -31,8 +31,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; import android.os.Trace; -import android.text.TextUtils; -import android.util.PathParser; import android.util.Slog; import android.util.SparseArray; import android.view.Display; @@ -404,8 +402,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) { mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND; } - mInfo.displayCutout = DisplayCutout.fromResources(res, mInfo.width, - mInfo.height); + mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res, + mInfo.width, mInfo.height); mInfo.type = Display.TYPE_BUILT_IN; mInfo.densityDpi = (int)(phys.density * 160 + 0.5f); mInfo.xDpi = phys.xDpi; diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 2949b92f82df..c7cdbefba723 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -264,14 +264,28 @@ abstract class HdmiCecLocalDevice { return handleRoutingChange(message); case Constants.MESSAGE_ROUTING_INFORMATION: return handleRoutingInformation(message); + case Constants.MESSAGE_REQUEST_ARC_INITIATION: + return handleRequestArcInitiate(message); + case Constants.MESSAGE_REQUEST_ARC_TERMINATION: + return handleRequestArcTermination(message); case Constants.MESSAGE_INITIATE_ARC: return handleInitiateArc(message); case Constants.MESSAGE_TERMINATE_ARC: return handleTerminateArc(message); + case Constants.MESSAGE_REPORT_ARC_INITIATED: + return handleReportArcInitiate(message); + case Constants.MESSAGE_REPORT_ARC_TERMINATED: + return handleReportArcTermination(message); + case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST: + return handleSystemAudioModeRequest(message); case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE: return handleSetSystemAudioMode(message); case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: return handleSystemAudioModeStatus(message); + case Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS: + return handleGiveSystemAudioModeStatus(message); + case Constants.MESSAGE_GIVE_AUDIO_STATUS: + return handleGiveAudioStatus(message); case Constants.MESSAGE_REPORT_AUDIO_STATUS: return handleReportAudioStatus(message); case Constants.MESSAGE_STANDBY: @@ -419,10 +433,18 @@ abstract class HdmiCecLocalDevice { return false; } + protected boolean handleGiveSystemAudioModeStatus(HdmiCecMessage message) { + return false; + } + protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { return false; } + protected boolean handleSystemAudioModeRequest(HdmiCecMessage message) { + return false; + } + protected boolean handleTerminateArc(HdmiCecMessage message) { return false; } @@ -431,10 +453,30 @@ abstract class HdmiCecLocalDevice { return false; } + protected boolean handleRequestArcInitiate(HdmiCecMessage message) { + return false; + } + + protected boolean handleRequestArcTermination(HdmiCecMessage message) { + return false; + } + + protected boolean handleReportArcInitiate(HdmiCecMessage message) { + return false; + } + + protected boolean handleReportArcTermination(HdmiCecMessage message) { + return false; + } + protected boolean handleReportAudioStatus(HdmiCecMessage message) { return false; } + protected boolean handleGiveAudioStatus(HdmiCecMessage message) { + return false; + } + @ServiceThreadOnly protected boolean handleStandby(HdmiCecMessage message) { assertRunOnServiceThread(); diff --git a/services/core/java/com/android/server/input/InputForwarder.java b/services/core/java/com/android/server/input/InputForwarder.java index 38a1cd745722..00af8398d0ff 100644 --- a/services/core/java/com/android/server/input/InputForwarder.java +++ b/services/core/java/com/android/server/input/InputForwarder.java @@ -19,7 +19,6 @@ package com.android.server.input; import android.app.IInputForwarder; import android.hardware.input.InputManagerInternal; import android.view.InputEvent; -import android.view.MotionEvent; import com.android.server.LocalServices; @@ -40,9 +39,7 @@ class InputForwarder extends IInputForwarder.Stub { @Override public boolean forwardEvent(InputEvent event) { - if (event instanceof MotionEvent) { - ((MotionEvent) event).setDisplayId(mDisplayId); - } + event.setDisplayId(mDisplayId); return mInputManagerInternal.injectInputEvent(event, INJECT_INPUT_EVENT_MODE_ASYNC); } }
\ No newline at end of file diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 442354bbb6b9..a49cf44dc775 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -481,7 +481,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags, packageName, uid); } - } catch (IllegalArgumentException e) { + } catch (IllegalArgumentException | SecurityException e) { Log.e(TAG, "Cannot adjust volume: direction=" + direction + ", stream=" + stream + ", flags=" + flags + ", packageName=" + packageName + ", uid=" + uid + ", useSuggested=" + useSuggested diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 5eb73971d1de..af4f4262450e 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -54,6 +54,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; @@ -116,9 +117,12 @@ abstract public class ManagedServices { // contains connections to all connected services, including app services // and system services private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>(); - // things that will be put into mServices as soon as they're ready - private final ArrayList<String> mServicesBinding = new ArrayList<>(); - private final ArraySet<String> mServicesRebinding = new ArraySet<>(); + /** + * The services that have been bound by us. If the service is also connected, it will also + * be in {@link #mServices}. + */ + private final ArrayList<Pair<ComponentName, Integer>> mServicesBound = new ArrayList<>(); + private final ArraySet<Pair<ComponentName, Integer>> mServicesRebinding = new ArraySet<>(); // lists the component names of all enabled (and therefore potentially connected) // app services for current profiles. @@ -917,13 +921,13 @@ abstract public class ManagedServices { final boolean isSystem) { if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid); - final String servicesBindingTag = name.toString() + "/" + userid; - if (mServicesBinding.contains(servicesBindingTag)) { - Slog.v(TAG, "Not registering " + name + " as bind is already in progress"); + final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid); + if (mServicesBound.contains(servicesBindingTag)) { + Slog.v(TAG, "Not registering " + name + " is already bound"); // stop registering this thing already! we're working on it return; } - mServicesBinding.add(servicesBindingTag); + mServicesBound.add(servicesBindingTag); final int N = mServices.size(); for (int i = N - 1; i >= 0; i--) { @@ -934,11 +938,7 @@ abstract public class ManagedServices { Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service); removeServiceLocked(i); if (info.connection != null) { - try { - mContext.unbindService(info.connection); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "failed to unbind " + name, e); - } + unbindService(info.connection, info.component, info.userid); } } } @@ -969,11 +969,11 @@ abstract public class ManagedServices { @Override public void onServiceConnected(ComponentName name, IBinder binder) { + Slog.v(TAG, getCaption() + " service connected: " + name); boolean added = false; ManagedServiceInfo info = null; synchronized (mMutex) { mServicesRebinding.remove(servicesBindingTag); - mServicesBinding.remove(servicesBindingTag); try { mService = asInterface(binder); info = newServiceInfo(mService, name, @@ -991,7 +991,6 @@ abstract public class ManagedServices { @Override public void onServiceDisconnected(ComponentName name) { - mServicesBinding.remove(servicesBindingTag); Slog.v(TAG, getCaption() + " connection lost: " + name); } @@ -999,12 +998,7 @@ abstract public class ManagedServices { public void onBindingDied(ComponentName name) { Slog.w(TAG, getCaption() + " binding died: " + name); synchronized (mMutex) { - mServicesBinding.remove(servicesBindingTag); - try { - mContext.unbindService(this); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "failed to unbind " + name, e); - } + unbindService(this, name, userid); if (!mServicesRebinding.contains(servicesBindingTag)) { mServicesRebinding.add(servicesBindingTag); mHandler.postDelayed(new Runnable() { @@ -1024,12 +1018,12 @@ abstract public class ManagedServices { serviceConnection, BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT, new UserHandle(userid))) { - mServicesBinding.remove(servicesBindingTag); + mServicesBound.remove(servicesBindingTag); Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); return; } } catch (SecurityException ex) { - mServicesBinding.remove(servicesBindingTag); + mServicesBound.remove(servicesBindingTag); Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex); } } @@ -1050,13 +1044,7 @@ abstract public class ManagedServices { if (name.equals(info.component) && info.userid == userid) { removeServiceLocked(i); if (info.connection != null) { - try { - mContext.unbindService(info.connection); - } catch (IllegalArgumentException ex) { - // something happened to the service: we think we have a connection - // but it's bogus. - Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex); - } + unbindService(info.connection, info.component, info.userid); } } } @@ -1121,7 +1109,18 @@ abstract public class ManagedServices { private void unregisterServiceImpl(IInterface service, int userid) { ManagedServiceInfo info = removeServiceImpl(service, userid); if (info != null && info.connection != null && !info.isGuest(this)) { - mContext.unbindService(info.connection); + unbindService(info.connection, info.component, info.userid); + } + } + + private void unbindService(ServiceConnection connection, ComponentName component, int userId) { + try { + mContext.unbindService(connection); + } catch (IllegalArgumentException e) { + Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e); + } + synchronized (mMutex) { + mServicesBound.remove(Pair.create(component, userId)); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 52f4461fd774..71c7c881619e 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -329,6 +329,8 @@ public class NotificationManagerService extends SystemService { private long[] mFallbackVibrationPattern; private boolean mUseAttentionLight; + boolean mHasLight = true; + boolean mLightEnabled; boolean mSystemReady; private boolean mDisableNotificationEffects; @@ -343,9 +345,9 @@ public class NotificationManagerService extends SystemService { private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN; // for enabling and disabling notification pulse behavior - private boolean mScreenOn = true; + boolean mScreenOn = true; protected boolean mInCall = false; - private boolean mNotificationPulseEnabled; + boolean mNotificationPulseEnabled; private Uri mInCallNotificationUri; private AudioAttributes mInCallNotificationAudioAttributes; @@ -1196,7 +1198,8 @@ public class NotificationManagerService extends SystemService { ContentResolver resolver = getContext().getContentResolver(); if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { boolean pulseEnabled = Settings.System.getIntForUser(resolver, - Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0; + Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) + != 0; if (mNotificationPulseEnabled != pulseEnabled) { mNotificationPulseEnabled = pulseEnabled; updateNotificationPulse(); @@ -1458,6 +1461,8 @@ public class NotificationManagerService extends SystemService { mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume); mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight); + mHasLight = + resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed); // Don't start allowing notifications until the setup wizard has run once. // After that, including subsequent boots, init with notifications turned on. @@ -3843,6 +3848,7 @@ public class NotificationManagerService extends SystemService { pw.println(" "); } pw.println(" mUseAttentionLight=" + mUseAttentionLight); + pw.println(" mHasLight=" + mHasLight); pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled); pw.println(" mSoundNotificationKey=" + mSoundNotificationKey); pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey); @@ -4840,8 +4846,7 @@ public class NotificationManagerService extends SystemService { // light // release the light boolean wasShowLights = mLights.remove(key); - if (record.getLight() != null && aboveThreshold - && ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) == 0)) { + if (canShowLightsLocked(record, aboveThreshold)) { mLights.add(key); updateLightsLocked(); if (mUseAttentionLight) { @@ -4852,7 +4857,19 @@ public class NotificationManagerService extends SystemService { updateLightsLocked(); } if (buzz || beep || blink) { - record.setInterruptive(true); + // Ignore summary updates because we don't display most of the information. + if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) { + if (DEBUG_INTERRUPTIVENESS) { + Log.v(TAG, "INTERRUPTIVENESS: " + + record.getKey() + " is not interruptive: summary"); + } + } else { + if (DEBUG_INTERRUPTIVENESS) { + Log.v(TAG, "INTERRUPTIVENESS: " + + record.getKey() + " is interruptive: alerted"); + } + record.setInterruptive(true); + } MetricsLogger.action(record.getLogMaker() .setCategory(MetricsEvent.NOTIFICATION_ALERT) .setType(MetricsEvent.TYPE_OPEN) @@ -4862,11 +4879,49 @@ public class NotificationManagerService extends SystemService { } @GuardedBy("mNotificationLock") + boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) { + // device lacks light + if (!mHasLight) { + return false; + } + // user turned lights off globally + if (!mNotificationPulseEnabled) { + return false; + } + // the notification/channel has no light + if (record.getLight() == null) { + return false; + } + // unimportant notification + if (!aboveThreshold) { + return false; + } + // suppressed due to DND + if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) { + return false; + } + // Suppressed because it's a silent update + final Notification notification = record.getNotification(); + if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { + return false; + } + // Suppressed because another notification in its group handles alerting + if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) { + return false; + } + // not if in call or the screen's on + if (mInCall || mScreenOn) { + return false; + } + + return true; + } + + @GuardedBy("mNotificationLock") boolean shouldMuteNotificationLocked(final NotificationRecord record) { // Suppressed because it's a silent update final Notification notification = record.getNotification(); - if(record.isUpdate - && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { + if (record.isUpdate && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) { return true; } @@ -4979,27 +5034,31 @@ public class NotificationManagerService extends SystemService { } protected void playInCallNotification() { - new Thread() { - @Override - public void run() { - final long identity = Binder.clearCallingIdentity(); - try { - final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); - if (player != null) { - if (mCallNotificationToken != null) { - player.stop(mCallNotificationToken); + if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL + && Settings.Secure.getInt(getContext().getContentResolver(), + Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) { + new Thread() { + @Override + public void run() { + final long identity = Binder.clearCallingIdentity(); + try { + final IRingtonePlayer player = mAudioManager.getRingtonePlayer(); + if (player != null) { + if (mCallNotificationToken != null) { + player.stop(mCallNotificationToken); + } + mCallNotificationToken = new Binder(); + player.play(mCallNotificationToken, mInCallNotificationUri, + mInCallNotificationAudioAttributes, + mInCallNotificationVolume, false); } - mCallNotificationToken = new Binder(); - player.play(mCallNotificationToken, mInCallNotificationUri, - mInCallNotificationAudioAttributes, - mInCallNotificationVolume, false); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(identity); } - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(identity); } - } - }.start(); + }.start(); + } } @GuardedBy("mToastQueue") diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index 75b9f1311b75..1ab05ec94476 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -443,6 +443,8 @@ public final class NotificationRecord { pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent); pw.println(prefix + "contentIntent=" + notification.contentIntent); pw.println(prefix + "deleteIntent=" + notification.deleteIntent); + pw.println(prefix + "number=" + notification.number); + pw.println(prefix + "groupAlertBehavior=" + notification.getGroupAlertBehavior()); pw.print(prefix + "tickerText="); if (!TextUtils.isEmpty(notification.tickerText)) { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 24fd3312f844..1954ed4bfa45 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1190,6 +1190,11 @@ public class ZenModeHelper { && Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0; + if (isWatch) { + Settings.Global.putInt(mContext.getContentResolver(), + Global.SHOW_ZEN_UPGRADE_NOTIFICATION, 0); + } + if (showNotification) { mNotificationManager.notify(TAG, SystemMessage.NOTE_ZEN_UPGRADE, createZenUpgradeNotification()); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c536e4dbea59..734a872b0fcc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -169,6 +169,7 @@ import android.content.pm.PackageList; import android.content.pm.PackageManager; import android.content.pm.PackageManager.LegacyPackageDeleteObserver; import android.content.pm.PackageManagerInternal; +import android.content.pm.PackageManagerInternal.CheckPermissionDelegate; import android.content.pm.PackageManagerInternal.PackageListObserver; import android.content.pm.PackageParser; import android.content.pm.PackageParser.ActivityIntentInfo; @@ -289,6 +290,8 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; +import com.android.internal.util.function.QuadFunction; +import com.android.internal.util.function.TriFunction; import com.android.server.AttributeCache; import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; @@ -363,6 +366,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiFunction; import java.util.function.Predicate; import dalvik.system.CloseGuard; @@ -1031,6 +1035,9 @@ public class PackageManagerService extends IPackageManager.Stub void receiveVerificationResponse(int verificationId); } + @GuardedBy("mPackages") + private CheckPermissionDelegate mCheckPermissionDelegate; + private class IntentVerifierProxy implements IntentFilterVerifier<ActivityIntentInfo> { private Context mContext; private ComponentName mIntentFilterVerifierComponent; @@ -5260,11 +5267,35 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int checkPermission(String permName, String pkgName, int userId) { + final CheckPermissionDelegate checkPermissionDelegate; + synchronized (mPackages) { + if (mCheckPermissionDelegate == null) { + return checkPermissionImpl(permName, pkgName, userId); + } + checkPermissionDelegate = mCheckPermissionDelegate; + } + return checkPermissionDelegate.checkPermission(permName, pkgName, userId, + PackageManagerService.this::checkPermissionImpl); + } + + private int checkPermissionImpl(String permName, String pkgName, int userId) { return mPermissionManager.checkPermission(permName, pkgName, getCallingUid(), userId); } @Override public int checkUidPermission(String permName, int uid) { + final CheckPermissionDelegate checkPermissionDelegate; + synchronized (mPackages) { + if (mCheckPermissionDelegate == null) { + return checkUidPermissionImpl(permName, uid); + } + checkPermissionDelegate = mCheckPermissionDelegate; + } + return checkPermissionDelegate.checkUidPermission(permName, uid, + PackageManagerService.this::checkUidPermissionImpl); + } + + private int checkUidPermissionImpl(String permName, int uid) { synchronized (mPackages) { final String[] packageNames = getPackagesForUid(uid); final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0) @@ -9150,6 +9181,16 @@ public class PackageManagerService extends IPackageManager.Stub } @GuardedBy("mPackages") + public CheckPermissionDelegate getCheckPermissionDelegateLocked() { + return mCheckPermissionDelegate; + } + + @GuardedBy("mPackages") + public void setCheckPermissionDelegateLocked(CheckPermissionDelegate delegate) { + mCheckPermissionDelegate = delegate; + } + + @GuardedBy("mPackages") private void notifyPackageUseLocked(String packageName, int reason) { final PackageParser.Package p = mPackages.get(packageName); if (p == null) { @@ -24150,6 +24191,20 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerService.this.notifyPackageUseLocked(packageName, reason); } } + + @Override + public CheckPermissionDelegate getCheckPermissionDelegate() { + synchronized (mPackages) { + return PackageManagerService.this.getCheckPermissionDelegateLocked(); + } + } + + @Override + public void setCheckPermissionDelegate(CheckPermissionDelegate delegate) { + synchronized (mPackages) { + PackageManagerService.this.setCheckPermissionDelegateLocked(delegate); + } + } } @Override diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java index a042fedf8b47..ec15c16981a8 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java @@ -21,19 +21,11 @@ import android.annotation.Nullable; import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.PermissionInfoFlags; -import android.content.pm.PackageParser.Permission; - -import com.android.server.pm.SharedUserSetting; -import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Set; /** * Internal interfaces to be used by other components within the system server. diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java index eca6f9f1ec47..14c985c090a3 100644 --- a/services/core/java/com/android/server/policy/BarController.java +++ b/services/core/java/com/android/server/policy/BarController.java @@ -196,7 +196,7 @@ public class BarController { } protected boolean skipAnimation() { - return false; + return !mWin.isDrawnLw(); } private int computeStateLw(boolean wasVis, boolean wasAnim, WindowState win, boolean change) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index b99f8d6c8170..5bc35e7296c3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -76,6 +76,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CO import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_BAR_EXPANDED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; @@ -4686,8 +4687,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { navTranslucent &= areTranslucentBarsAllowed(); } boolean statusBarExpandedNotKeyguard = !isKeyguardShowing && mStatusBar != null - && mStatusBar.getAttrs().height == MATCH_PARENT - && mStatusBar.getAttrs().width == MATCH_PARENT; + && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_STATUS_BAR_EXPANDED) != 0; // When the navigation bar isn't visible, we put up a fake input window to catch all // touch events. This way we can detect when the user presses anywhere to bring back the @@ -5690,7 +5690,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // Take note if a window wants to acquire a sleep token. - if (win.isVisibleLw() && (attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0 + if ((attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0 && win.canAcquireSleepToken()) { mWindowSleepTokenNeeded = true; } @@ -5746,9 +5746,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mStatusBarController.setShowTransparent(true /* transparent */); } - WindowManager.LayoutParams statusBarAttrs = mStatusBar.getAttrs(); - boolean statusBarExpanded = statusBarAttrs.height == MATCH_PARENT - && statusBarAttrs.width == MATCH_PARENT; + boolean statusBarExpanded = + (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_STATUS_BAR_EXPANDED) != 0; boolean topAppHidesStatusBar = topAppHidesStatusBar(); if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent || statusBarExpanded) { diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index dd6d71e3b7a3..4c88bf44d5a8 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -72,7 +72,7 @@ public class BatterySaverStateMachine { @GuardedBy("mLock") private int mBatteryLevel; - /** Whether the battery level is considered to be "low" or not.*/ + /** Whether the battery level is considered to be "low" or not. */ @GuardedBy("mLock") private boolean mIsBatteryLevelLow; @@ -84,6 +84,9 @@ public class BatterySaverStateMachine { @GuardedBy("mLock") private boolean mSettingBatterySaverEnabledSticky; + /** Config flag to track if battery saver's sticky behaviour is disabled. */ + private final boolean mBatterySaverStickyBehaviourDisabled; + /** * Previously known value of Global.LOW_POWER_MODE_TRIGGER_LEVEL. * (Currently only used in dumpsys.) @@ -124,6 +127,9 @@ public class BatterySaverStateMachine { mLock = lock; mContext = context; mBatterySaverController = batterySaverController; + + mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled); } private boolean isBatterySaverEnabled() { @@ -304,7 +310,7 @@ public class BatterySaverStateMachine { BatterySaverController.REASON_PLUGGED_IN, "Plugged in"); - } else if (mSettingBatterySaverEnabledSticky) { + } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) { // Re-enable BS. enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true, BatterySaverController.REASON_STICKY_RESTORE, @@ -383,8 +389,9 @@ public class BatterySaverStateMachine { putGlobalSetting(Global.LOW_POWER_MODE, enable ? 1 : 0); if (manual) { - mSettingBatterySaverEnabledSticky = enable; - putGlobalSetting(Global.LOW_POWER_MODE_STICKY, enable ? 1 : 0); + mSettingBatterySaverEnabledSticky = !mBatterySaverStickyBehaviourDisabled && enable; + putGlobalSetting(Global.LOW_POWER_MODE_STICKY, + mSettingBatterySaverEnabledSticky ? 1 : 0); } mBatterySaverController.enableBatterySaver(enable, intReason); @@ -449,6 +456,8 @@ public class BatterySaverStateMachine { pw.println(mSettingBatterySaverEnabledSticky); pw.print(" mSettingBatterySaverTriggerThreshold="); pw.println(mSettingBatterySaverTriggerThreshold); + pw.print(" mBatterySaverStickyBehaviourDisabled="); + pw.println(mBatterySaverStickyBehaviourDisabled); } } diff --git a/services/core/java/com/android/server/slice/PinnedSliceState.java b/services/core/java/com/android/server/slice/PinnedSliceState.java index 4e7fb969f398..e139ab86775d 100644 --- a/services/core/java/com/android/server/slice/PinnedSliceState.java +++ b/services/core/java/com/android/server/slice/PinnedSliceState.java @@ -154,8 +154,8 @@ public class PinnedSliceState { } ContentProviderClient getClient() { - ContentProviderClient client = - mService.getContext().getContentResolver().acquireContentProviderClient(mUri); + ContentProviderClient client = mService.getContext().getContentResolver() + .acquireUnstableContentProviderClient(mUri); if (client == null) return null; client.setDetectNotResponding(SLICE_TIMEOUT); return client; diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index ea34346019d1..ded2c1536bb8 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -42,6 +42,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Binder; @@ -396,30 +397,11 @@ public class SliceManagerService extends ISliceManager.Stub { private String getProviderPkg(Uri uri, int user) { long ident = Binder.clearCallingIdentity(); try { - IBinder token = new Binder(); - IActivityManager activityManager = ActivityManager.getService(); - ContentProviderHolder holder = null; String providerName = getUriWithoutUserId(uri).getAuthority(); - try { - try { - holder = activityManager.getContentProviderExternal( - providerName, getUserIdFromUri(uri, user), token); - if (holder != null && holder.info != null) { - return holder.info.packageName; - } else { - return null; - } - } finally { - if (holder != null && holder.provider != null) { - activityManager.removeContentProviderExternal(providerName, token); - } - } - } catch (RemoteException e) { - // Can't happen. - throw e.rethrowAsRuntimeException(); - } + ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser( + providerName, 0, getUserIdFromUri(uri, user)); + return provider.packageName; } finally { - // I know, the double finally seems ugly, but seems safest for the identity. Binder.restoreCallingIdentity(ident); } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 547ab0ed443d..9d68c63cc38c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -51,7 +51,6 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.res.Resources; -import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; @@ -76,7 +75,6 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.provider.Settings; import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; import android.service.wallpaper.IWallpaperService; @@ -338,102 +336,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } } - /** - * Observes changes of theme settings. It will check whether to call - * notifyWallpaperColorsChanged by the current theme and updated theme. - * The light theme and dark theme are controlled by the hint values in Wallpaper colors, - * threrfore, if light theme mode is chosen, HINT_SUPPORTS_DARK_THEME in hint will be - * removed and then notify listeners. - */ - private class ThemeSettingsObserver extends ContentObserver { - - public ThemeSettingsObserver(Handler handler) { - super(handler); - } - - public void startObserving(Context context) { - context.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.THEME_MODE), - false, - this); - } - - public void stopObserving(Context context) { - context.getContentResolver().unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange) { - onThemeSettingsChanged(); - } - } - - /** - * Check whether to call notifyWallpaperColorsChanged. Assumed that the theme mode - * was wallpaper theme mode and dark wallpaper was set, therefoe, the theme was dark. - * Then theme mode changing to dark theme mode, however, theme should not update since - * theme was dark already. - */ - private boolean needUpdateLocked(WallpaperColors colors, int themeMode) { - if (colors == null) { - return false; - } - - if (themeMode == mThemeMode) { - return false; - } - - boolean result = true; - boolean supportDarkTheme = - (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; - switch (themeMode) { - case Settings.Secure.THEME_MODE_WALLPAPER: - if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) { - result = supportDarkTheme; - } else { - result = !supportDarkTheme; - } - break; - case Settings.Secure.THEME_MODE_LIGHT: - if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) { - result = supportDarkTheme; - } - break; - case Settings.Secure.THEME_MODE_DARK: - if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) { - result = !supportDarkTheme; - } - break; - default: - Slog.w(TAG, "unkonwn theme mode " + themeMode); - return false; - } - mThemeMode = themeMode; - return result; - } - - void onThemeSettingsChanged() { - WallpaperData wallpaper; - synchronized (mLock) { - wallpaper = mWallpaperMap.get(mCurrentUserId); - int updatedThemeMode = Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.THEME_MODE, - Settings.Secure.THEME_MODE_WALLPAPER); - - if (DEBUG) { - Slog.v(TAG, "onThemeSettingsChanged, mode = " + updatedThemeMode); - } - - if (!needUpdateLocked(wallpaper.primaryColors, updatedThemeMode)) { - return; - } - } - - if (wallpaper != null) { - notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM); - } - } - void notifyLockWallpaperChanged() { final IWallpaperManagerCallback cb = mKeyguardListener; if (cb != null) { @@ -511,7 +413,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } userAllColorListeners.finishBroadcast(); } - wallpaperColors = getThemeColorsLocked(wallpaperColors); } final int count = colorListeners.size(); @@ -580,40 +481,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } /** - * We can easily change theme by modified colors hint. This function will check - * current theme mode and return the WallpaperColors fit current theme mode. - * If color need modified, it will return a copied WallpaperColors which - * its ColorsHint is modified to fit current theme mode. - * - * @param colors a wallpaper primary colors representation - */ - private WallpaperColors getThemeColorsLocked(WallpaperColors colors) { - if (colors == null) { - Slog.w(TAG, "Cannot get theme colors because WallpaperColors is null."); - return null; - } - - int colorHints = colors.getColorHints(); - boolean supportDarkTheme = (colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; - if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER || - (mThemeMode == Settings.Secure.THEME_MODE_LIGHT && !supportDarkTheme) || - (mThemeMode == Settings.Secure.THEME_MODE_DARK && supportDarkTheme)) { - return colors; - } - - WallpaperColors themeColors = new WallpaperColors(colors.getPrimaryColor(), - colors.getSecondaryColor(), colors.getTertiaryColor()); - - if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) { - colorHints &= ~WallpaperColors.HINT_SUPPORTS_DARK_THEME; - } else if (mThemeMode == Settings.Secure.THEME_MODE_DARK) { - colorHints |= WallpaperColors.HINT_SUPPORTS_DARK_THEME; - } - themeColors.setColorHints(colorHints); - return themeColors; - } - - /** * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped * for display. */ @@ -809,7 +676,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>(); int mCurrentUserId = UserHandle.USER_NULL; boolean mInAmbientMode; - int mThemeMode; static class WallpaperData { @@ -868,7 +734,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub long lastDiedTime; boolean wallpaperUpdating; WallpaperObserver wallpaperObserver; - ThemeSettingsObserver themeSettingsObserver; /** * List of callbacks registered they should each be notified when the wallpaper is changed. @@ -1414,10 +1279,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub wallpaper.wallpaperObserver.stopWatching(); wallpaper.wallpaperObserver = null; } - if (wallpaper.themeSettingsObserver != null) { - wallpaper.themeSettingsObserver.stopObserving(mContext); - wallpaper.themeSettingsObserver = null; - } } } @@ -1501,13 +1362,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper); systemWallpaper.wallpaperObserver.startWatching(); } - if (systemWallpaper.themeSettingsObserver == null) { - systemWallpaper.themeSettingsObserver = new ThemeSettingsObserver(null); - systemWallpaper.themeSettingsObserver.startObserving(mContext); - } - mThemeMode = Settings.Secure.getInt( - mContext.getContentResolver(), Settings.Secure.THEME_MODE, - Settings.Secure.THEME_MODE_WALLPAPER); switchWallpaper(systemWallpaper, reply); } @@ -1981,7 +1835,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } synchronized (mLock) { - return getThemeColorsLocked(wallpaperData.primaryColors); + return wallpaperData.primaryColors; } } diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java index 0a49c139ad03..bc8c17db6abe 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationController.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java @@ -196,12 +196,6 @@ public class BoundsAnimationController { @Override public void onAnimationStart(Animator animation) { - if (!mTarget.isAttached()) { - // No point of trying to animate something that isn't attached to the hierarchy - // anymore. - cancel(); - } - if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget + " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState + " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState); @@ -216,13 +210,15 @@ public class BoundsAnimationController { // Ensure that we have prepared the target for animation before we trigger any size // changes, so it can swap surfaces in to appropriate modes, or do as it wishes // otherwise. + boolean continueAnimation; if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) { - mTarget.onAnimationStart(mSchedulePipModeChangedState == + continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */); // When starting an animation from fullscreen, pause here and wait for the // windows-drawn signal before we start the rest of the transition down into PiP. - if (mMoveFromFullscreen && mTarget.shouldDeferStartOnMoveToFullscreen()) { + if (continueAnimation && mMoveFromFullscreen + && mTarget.shouldDeferStartOnMoveToFullscreen()) { pause(); } } else if (mPrevSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END && @@ -231,8 +227,19 @@ public class BoundsAnimationController { // client will not currently receive any picture-in-picture mode change callbacks. // However, we still need to report to them that they are leaving PiP, so this will // force an update via a mode changed callback. - mTarget.onAnimationStart(true /* schedulePipModeChangedCallback */, - true /* forceUpdate */); + continueAnimation = mTarget.onAnimationStart( + true /* schedulePipModeChangedCallback */, true /* forceUpdate */); + } else { + // The animation is already running, but we should check that the TaskStack is still + // valid before continuing with the animation + continueAnimation = mTarget.isAttached(); + } + + if (!continueAnimation) { + // No point of trying to animate something that isn't attached to the hierarchy + // anymore. + cancel(); + return; } // Immediately update the task bounds if they have to become larger, but preserve @@ -354,6 +361,9 @@ public class BoundsAnimationController { if (DEBUG) Slog.d(TAG, "cancel: mTarget=" + mTarget); mSkipAnimationEnd = true; super.cancel(); + + // Reset the thread priority of the animation thread if the bounds animation is canceled + updateBooster(); } /** diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java index d66b42fba0a4..5cb80de1a36d 100644 --- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java +++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java @@ -30,8 +30,9 @@ interface BoundsAnimationTarget { * * @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed * callbacks + * @return whether to continue the animation */ - void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate); + boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate); /** * @return Whether the animation should be paused waiting for the windows to draw before diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f74216a6d44d..0ca8e1aae193 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1249,11 +1249,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo cutout, mInitialDisplayWidth, mInitialDisplayHeight); } final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); - final Path bounds = cutout.getBounds().getBoundaryPath(); + final List<Rect> bounds = WmDisplayCutout.computeSafeInsets( + cutout, mInitialDisplayWidth, mInitialDisplayHeight) + .getDisplayCutout().getBoundingRects(); transformPhysicalToLogicalCoordinates(rotation, mInitialDisplayWidth, mInitialDisplayHeight, mTmpMatrix); - bounds.transform(mTmpMatrix); - return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(bounds), + final Region region = Region.obtain(); + for (int i = 0; i < bounds.size(); i++) { + final Rect rect = bounds.get(i); + final RectF rectF = new RectF(bounds.get(i)); + mTmpMatrix.mapRect(rectF); + rectF.round(rect); + region.op(rect, Op.UNION); + } + + return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(region), rotated ? mInitialDisplayHeight : mInitialDisplayWidth, rotated ? mInitialDisplayWidth : mInitialDisplayHeight); } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index 281e0a8441e2..a626663c2e67 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -40,6 +40,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Process; import android.os.RemoteException; +import android.os.Trace; import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; @@ -620,6 +621,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { private void updateInputWindows(boolean inDrag) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "updateInputWindows"); + // TODO: multi-display navInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION, DEFAULT_DISPLAY); pipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP, DEFAULT_DISPLAY); @@ -645,6 +648,8 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { mService.mInputManager.setInputWindows(mInputWindowHandles, mFocusedInputWindowHandle); clearInputWindowHandlesLw(); + + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } @Override diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index e01cebde67ca..9075b6c7fa49 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -1645,9 +1645,14 @@ public class TaskStack extends WindowContainer<Task> implements } @Override // AnimatesBounds - public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) { + public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) { // Hold the lock since this is called from the BoundsAnimator running on the UiThread synchronized (mService.mWindowMap) { + if (!isAttached()) { + // Don't run the animation if the stack is already detached + return false; + } + mBoundsAnimatingRequested = false; mBoundsAnimating = true; mCancelCurrentBoundsAnimation = false; @@ -1677,6 +1682,7 @@ public class TaskStack extends WindowContainer<Task> implements controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate); } } + return true; } @Override // AnimatesBounds @@ -1720,41 +1726,47 @@ public class TaskStack extends WindowContainer<Task> implements @Override public boolean isAttached() { - return mDisplayContent != null; + synchronized (mService.mWindowMap) { + return mDisplayContent != null; + } } /** * Called immediately prior to resizing the tasks at the end of the pinned stack animation. */ public void onPipAnimationEndResize() { - mBoundsAnimating = false; - for (int i = 0; i < mChildren.size(); i++) { - final Task t = mChildren.get(i); - t.clearPreserveNonFloatingState(); + synchronized (mService.mWindowMap) { + mBoundsAnimating = false; + for (int i = 0; i < mChildren.size(); i++) { + final Task t = mChildren.get(i); + t.clearPreserveNonFloatingState(); + } + mService.requestTraversal(); } - mService.requestTraversal(); } @Override public boolean shouldDeferStartOnMoveToFullscreen() { - // Workaround for the recents animation -- normally we need to wait for the new activity to - // show before starting the PiP animation, but because we start and show the home activity - // early for the recents animation prior to the PiP animation starting, there is no - // subsequent all-drawn signal. In this case, we can skip the pause when the home stack is - // already visible and drawn. - final TaskStack homeStack = mDisplayContent.getHomeStack(); - if (homeStack == null) { - return true; - } - final Task homeTask = homeStack.getTopChild(); - if (homeTask == null) { - return true; - } - final AppWindowToken homeApp = homeTask.getTopVisibleAppToken(); - if (!homeTask.isVisible() || homeApp == null) { - return true; + synchronized (mService.mWindowMap) { + // Workaround for the recents animation -- normally we need to wait for the new activity + // to show before starting the PiP animation, but because we start and show the home + // activity early for the recents animation prior to the PiP animation starting, there + // is no subsequent all-drawn signal. In this case, we can skip the pause when the home + // stack is already visible and drawn. + final TaskStack homeStack = mDisplayContent.getHomeStack(); + if (homeStack == null) { + return true; + } + final Task homeTask = homeStack.getTopChild(); + if (homeTask == null) { + return true; + } + final AppWindowToken homeApp = homeTask.getTopVisibleAppToken(); + if (!homeTask.isVisible() || homeApp == null) { + return true; + } + return !homeApp.allDrawn; } - return !homeApp.allDrawn; } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 399078a6be37..54703b3c3c37 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2180,8 +2180,6 @@ public class WindowManagerService extends IWindowManager.Stub result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0; - mInputMonitor.updateInputWindowsLw(true /*force*/); - if (DEBUG_LAYOUT) { Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString()); } @@ -5666,9 +5664,9 @@ public class WindowManagerService extends IWindowManager.Stub boolean imWindowChanged = false; if (mInputMethodWindow != null) { final WindowState prevTarget = mInputMethodTarget; + final WindowState newTarget = displayContent.computeImeTarget(true /* updateImeTarget*/); - imWindowChanged = prevTarget != newTarget; if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 89efe12927ba..9e1191d2c1ef 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -2,6 +2,8 @@ cc_library_static { name: "libservices.core", defaults: ["libservices.core-libs"], + cpp_std: "c++17", + cflags: [ "-Wall", "-Werror", diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 1f1b3f88622a..252a1fdb7416 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -722,7 +722,7 @@ public final class SystemServer { // Tracks cpu time spent in binder calls traceBeginAndSlog("StartBinderCallsStatsService"); - BinderCallsStatsService.start(); + mSystemServiceManager.startService(BinderCallsStatsService.LifeCycle.class); traceEnd(); } diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java index 5af3c299bfc1..cfcba3a84f51 100644 --- a/services/net/java/android/net/netlink/NetlinkSocket.java +++ b/services/net/java/android/net/netlink/NetlinkSocket.java @@ -59,10 +59,9 @@ public class NetlinkSocket { final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; final long IO_TIMEOUT = 300L; - FileDescriptor fd; + final FileDescriptor fd = forProto(nlProto); try { - fd = forProto(nlProto); connectToKernel(fd); sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT); final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); @@ -96,9 +95,9 @@ public class NetlinkSocket { } catch (SocketException e) { Log.e(TAG, errPrefix, e); throw new ErrnoException(errPrefix, EIO, e); + } finally { + IoUtils.closeQuietly(fd); } - - IoUtils.closeQuietly(fd); } public static FileDescriptor forProto(int nlProto) throws ErrnoException { diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java index e5c6c6e51430..412e8445fef9 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java @@ -141,4 +141,15 @@ public class AccessibilityServiceConnectionTest { when(mMockUserState.getBindingServicesLocked()) .thenReturn(new HashSet<>(Arrays.asList(componentName))); } + + @Test + public void binderDied_keysGetFlushed() { + IBinder mockBinder = mock(IBinder.class); + setServiceBinding(COMPONENT_NAME); + mConnection.bindLocked(); + mConnection.onServiceConnected(COMPONENT_NAME, mockBinder); + mConnection.binderDied(); + assertTrue(mConnection.getServiceInfo().crashed); + verify(mMockKeyEventDispatcher).flush(mConnection); + } } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java new file mode 100644 index 000000000000..28b37c58c799 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/am/ActivityOptionsTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.am; + +import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; +import static org.junit.Assert.assertEquals; + +import android.app.ActivityOptions; +import android.os.Bundle; +import android.os.Debug; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.FlakyTest; +import android.support.test.filters.MediumTest; +import android.support.test.runner.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + + +/** + * atest FrameworksServicesTests:ActivityOptionsTest + */ +@MediumTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class ActivityOptionsTest { + + @Test + public void testMerge_NoClobber() { + // Construct some options with set values + ActivityOptions opts = ActivityOptions.makeBasic(); + opts.setLaunchDisplayId(Integer.MAX_VALUE); + opts.setLaunchActivityType(ACTIVITY_TYPE_STANDARD); + opts.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + opts.setAvoidMoveToFront(); + opts.setLaunchTaskId(Integer.MAX_VALUE); + opts.setLockTaskEnabled(true); + opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE); + opts.setTaskOverlay(true, true); + opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT); + Bundle optsBundle = opts.toBundle(); + + // Try and merge the constructed options with a new set of options + optsBundle.putAll(ActivityOptions.makeBasic().toBundle()); + + // Ensure the set values are not clobbered + ActivityOptions restoredOpts = ActivityOptions.fromBundle(optsBundle); + assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchDisplayId()); + assertEquals(ACTIVITY_TYPE_STANDARD, restoredOpts.getLaunchActivityType()); + assertEquals(WINDOWING_MODE_FULLSCREEN, restoredOpts.getLaunchWindowingMode()); + assertEquals(true, restoredOpts.getAvoidMoveToFront()); + assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId()); + assertEquals(true, restoredOpts.getLockTaskMode()); + assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint()); + assertEquals(true, restoredOpts.getTaskOverlay()); + assertEquals(true, restoredOpts.canTaskOverlayResume()); + assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, + restoredOpts.getSplitScreenCreateMode()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java index 7f55824b3082..420987d03509 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.when; +import android.app.ActivityManagerInternal; import android.app.KeyguardManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; @@ -94,11 +95,11 @@ public class ActivityStartInterceptorTest { @Mock private UserManager mUserManager; @Mock - private UserController mUserController; - @Mock private KeyguardManager mKeyguardManager; @Mock private PackageManagerService mPackageManager; + @Mock + private ActivityManagerInternal mAmInternal; private ActivityStartInterceptor mInterceptor; private ActivityInfo mAInfo = new ActivityInfo(); @@ -107,11 +108,15 @@ public class ActivityStartInterceptorTest { public void setUp() { MockitoAnnotations.initMocks(this); mService.mAm = mAm; - mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext, - mUserController); + mService.mAmInternal = mAmInternal; + mInterceptor = new ActivityStartInterceptor(mService, mSupervisor, mContext); mInterceptor.setStates(TEST_USER_ID, TEST_REAL_CALLING_PID, TEST_REAL_CALLING_UID, TEST_START_FLAGS, TEST_CALLING_PACKAGE); + // Mock ActivityManagerInternal + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.addService(ActivityManagerInternal.class, mAmInternal); + // Mock DevicePolicyManagerInternal LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); LocalServices.addService(DevicePolicyManagerInternal.class, @@ -193,7 +198,7 @@ public class ActivityStartInterceptorTest { @Test public void testWorkChallenge() { // GIVEN that the user the activity is starting as is currently locked - when(mUserController.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true); + when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true); // THEN calling intercept returns true mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 41c89554b1a4..f2d3eb6acd47 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -106,13 +106,15 @@ public class ActivityTestsBase { } protected ActivityTaskManagerService createActivityTaskManagerService() { - final TestActivityTaskManagerService atm = spy(new TestActivityTaskManagerService(mContext)); + final TestActivityTaskManagerService atm = + spy(new TestActivityTaskManagerService(mContext)); setupActivityManagerService(atm); return atm; } - protected ActivityManagerService createActivityManagerService() { - final TestActivityTaskManagerService atm = spy(new TestActivityTaskManagerService(mContext)); + ActivityManagerService createActivityManagerService() { + final TestActivityTaskManagerService atm = + spy(new TestActivityTaskManagerService(mContext)); return setupActivityManagerService(atm); } diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index a4e4409f3eb9..3547b0ddcadf 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -108,37 +108,6 @@ public class RecentTasksTest extends ActivityTestsBase { private CallbacksRecorder mCallbacksRecorder; - class TestUserController extends UserController { - TestUserController(ActivityManagerService service) { - super(service); - } - - @Override - int[] getCurrentProfileIds() { - return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID }; - } - - @Override - Set<Integer> getProfileIds(int userId) { - Set<Integer> profileIds = new HashSet<>(); - profileIds.add(TEST_USER_0_ID); - profileIds.add(TEST_QUIET_USER_ID); - return profileIds; - } - - @Override - UserInfo getUserInfo(int userId) { - switch (userId) { - case TEST_USER_0_ID: - case TEST_USER_1_ID: - return DEFAULT_USER_INFO; - case TEST_QUIET_USER_ID: - return QUIET_USER_INFO; - } - return null; - } - } - @Before @Override public void setUp() throws Exception { @@ -829,7 +798,7 @@ public class RecentTasksTest extends ActivityTestsBase { @Override protected RecentTasks createRecentTasks() { - return new TestRecentTasks(this, mTaskPersister, new TestUserController(mAm)); + return new TestRecentTasks(this, mTaskPersister); } @Override @@ -954,9 +923,33 @@ public class RecentTasksTest extends ActivityTestsBase { boolean lastAllowed; - TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister, - UserController userController) { - super(service, taskPersister, userController); + TestRecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) { + super(service, taskPersister); + } + + @Override + Set<Integer> getProfileIds(int userId) { + Set<Integer> profileIds = new HashSet<>(); + profileIds.add(TEST_USER_0_ID); + profileIds.add(TEST_QUIET_USER_ID); + return profileIds; + } + + @Override + UserInfo getUserInfo(int userId) { + switch (userId) { + case TEST_USER_0_ID: + case TEST_USER_1_ID: + return DEFAULT_USER_INFO; + case TEST_QUIET_USER_ID: + return QUIET_USER_INFO; + } + return null; + } + + @Override + int[] getCurrentProfileIds() { + return new int[] { TEST_USER_0_ID, TEST_QUIET_USER_ID }; } @Override diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java index 2c47a9432eff..1d378020fa4f 100644 --- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java +++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java @@ -37,6 +37,7 @@ import android.graphics.Matrix; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.RectF; import android.os.IBinder; import android.os.UserHandle; import android.support.test.InstrumentationRegistry; @@ -172,15 +173,14 @@ public class PhoneWindowManagerTestBase { } private static DisplayCutout displayCutoutForRotation(int rotation) { - Path p = new Path(); - p.addRect(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT, - Path.Direction.CCW); + RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT); Matrix m = new Matrix(); transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m); - p.transform(m); + m.mapRect(rectF); - return DisplayCutout.fromBounds(p); + return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top, + (int) rectF.right, (int) rectF.bottom); } static class TestContextWrapper extends ContextWrapper { diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java index 5b247253fd9c..0764a56af18f 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.ContentResolver; +import android.content.res.Resources; import android.provider.Settings.Global; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -48,12 +49,18 @@ public class BatterySaverStateMachineTest { private BatterySaverController mMockBatterySaverController; private Device mDevice; private TestableBatterySaverStateMachine mTarget; + private Resources mMockResources; private class MyMockContext extends MockContext { @Override public ContentResolver getContentResolver() { return mMockContextResolver; } + + @Override + public Resources getResources() { + return mMockResources; + } } private DevicePersistedState mPersistedState; @@ -157,11 +164,15 @@ public class BatterySaverStateMachineTest { mMockContext = new MyMockContext(); mMockContextResolver = mock(ContentResolver.class); mMockBatterySaverController = mock(BatterySaverController.class); + mMockResources = mock(Resources.class); doAnswer((inv) -> mDevice.batterySaverEnabled = inv.getArgument(0)) .when(mMockBatterySaverController).enableBatterySaver(anyBoolean(), anyInt()); when(mMockBatterySaverController.isEnabled()) .thenAnswer((inv) -> mDevice.batterySaverEnabled); + when(mMockResources.getBoolean( + com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled)) + .thenReturn(false); mPersistedState = new DevicePersistedState(); initDevice(); @@ -173,7 +184,6 @@ public class BatterySaverStateMachineTest { mTarget = new TestableBatterySaverStateMachine(); mDevice.pushBatteryStatus(); - mDevice.pushGlobalSettings(); mTarget.onBootCompleted(); } @@ -498,8 +508,83 @@ public class BatterySaverStateMachineTest { } @Test - public void testNoAutoBatterySaver_fromAdb() { + public void testAutoBatterySaver_withStickyDisabled() { + when(mMockResources.getBoolean( + com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled)) + .thenReturn(true); + initDevice(); + mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50); + + mTarget.setBatterySaverEnabledManually(true); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(100, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + mDevice.setBatteryLevel(30); + + assertEquals(true, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + assertEquals(true, mPersistedState.batteryLow); + + mDevice.setBatteryLevel(80); + + assertEquals(false, mDevice.batterySaverEnabled); // Not sticky. + assertEquals(80, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + mDevice.setPowered(true); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(80, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + mDevice.setBatteryLevel(30); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(30, mPersistedState.batteryLevel); + assertEquals(true, mPersistedState.batteryLow); + + mDevice.setPowered(false); + + assertEquals(true, mDevice.batterySaverEnabled); // Restores BS. + assertEquals(30, mPersistedState.batteryLevel); + assertEquals(true, mPersistedState.batteryLow); + + mDevice.setPowered(true); + mDevice.setBatteryLevel(90); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + initDevice(); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + mDevice.setPowered(false); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + mTarget.setBatterySaverEnabledManually(false); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + + initDevice(); + + assertEquals(false, mDevice.batterySaverEnabled); + assertEquals(90, mPersistedState.batteryLevel); + assertEquals(false, mPersistedState.batteryLow); + } + + @Test + public void testNoAutoBatterySaver_fromAdb() { assertEquals(0, mDevice.getLowPowerModeTriggerLevel()); assertEquals(false, mDevice.batterySaverEnabled); diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java index ff631e74e004..08b522c0c66e 100644 --- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java @@ -151,11 +151,13 @@ public class BoundsAnimationControllerTests extends WindowTestsBase { } @Override - public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) { + public boolean onAnimationStart(boolean schedulePipModeChangedCallback, + boolean forceUpdate) { mAwaitingAnimationStart = false; mAnimationStarted = true; mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback; mForcePipModeChangedCallback = forceUpdate; + return true; } @Override diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index b19373efd1b0..21402cee0b55 100644 --- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -59,7 +59,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis, int windowFlags, Rect taskBounds) { final GraphicBuffer buffer = GraphicBuffer.create(width, height, PixelFormat.RGBA_8888, - GraphicBuffer.USAGE_SW_READ_NEVER | GraphicBuffer.USAGE_SW_WRITE_NEVER); + GraphicBuffer.USAGE_SW_READ_RARELY | GraphicBuffer.USAGE_SW_WRITE_NEVER); final TaskSnapshot snapshot = new TaskSnapshot(buffer, ORIENTATION_PORTRAIT, contentInsets, false, 1.0f, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* systemUiVisibility */, false /* isTranslucent */); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index 78099996a1a0..bdba3d5cd677 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -19,7 +19,9 @@ import static android.app.Notification.GROUP_ALERT_ALL; import static android.app.Notification.GROUP_ALERT_CHILDREN; import static android.app.Notification.GROUP_ALERT_SUMMARY; import static android.app.NotificationManager.IMPORTANCE_HIGH; +import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_MIN; +import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; @@ -149,6 +151,9 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.setFallbackVibrationPattern(FALLBACK_VIBRATION_PATTERN); mService.setUsageStats(mUsageStats); mService.setAccessibilityManager(accessibilityManager); + mService.mScreenOn = false; + mService.mInCall = false; + mService.mNotificationPulseEnabled = true; } // @@ -216,8 +221,13 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } private NotificationRecord getLightsNotification() { + return getNotificationRecord(mId, false /* insistent */, false /* once */, + false /* noisy */, false /* buzzy*/, true /* lights */); + } + + private NotificationRecord getLightsOnceNotification() { return getNotificationRecord(mId, false /* insistent */, true /* once */, - false /* noisy */, true /* buzzy*/, true /* lights */); + false /* noisy */, false /* buzzy*/, true /* lights */); } private NotificationRecord getCustomLightsNotification() { @@ -244,6 +254,12 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { groupKey, groupAlertBehavior, false); } + private NotificationRecord getLightsNotificationRecord(String groupKey, + int groupAlertBehavior) { + return getNotificationRecord(mId, false, false, false, false, true /*lights*/, true, true, + true, groupKey, groupAlertBehavior, false); + } + private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once, boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration, boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior, @@ -369,6 +385,10 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mVibrator, never()).cancel(); } + private void verifyNeverLights() { + verify(mLight, never()).setFlashing(anyInt(), anyInt(), anyInt(), anyInt()); + } + private void verifyLights() { verify(mLight, times(1)).setFlashing(anyInt(), anyInt(), anyInt(), anyInt()); } @@ -712,7 +732,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { mService.buzzBeepBlinkLocked(summary); verifyBeepLooped(); - assertTrue(summary.isInterruptive()); + // summaries are never interruptive for notification counts + assertFalse(summary.isInterruptive()); } @Test @@ -990,6 +1011,156 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt()); } + @Test + public void testLightsScreenOn() { + mService.mScreenOn = true; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsInCall() { + mService.mInCall = true; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsSilentUpdate() { + NotificationRecord r = getLightsOnceNotification(); + mService.buzzBeepBlinkLocked(r); + verifyLights(); + assertTrue(r.isInterruptive()); + + r = getLightsOnceNotification(); + r.isUpdate = true; + mService.buzzBeepBlinkLocked(r); + // checks that lights happened once, i.e. this new call didn't trigger them again + verifyLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsUnimportant() { + NotificationRecord r = getLightsNotification(); + r.setImportance(IMPORTANCE_LOW, "testing"); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsNoLights() { + NotificationRecord r = getQuietNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsNoLightOnDevice() { + mService.mHasLight = false; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsLightsOffGlobally() { + mService.mNotificationPulseEnabled = false; + NotificationRecord r = getLightsNotification(); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testLightsDndIntercepted() { + NotificationRecord r = getLightsNotification(); + r.setSuppressedVisualEffects(SUPPRESSED_EFFECT_LIGHTS); + mService.buzzBeepBlinkLocked(r); + verifyNeverLights(); + assertFalse(r.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryNoLightsChild() { + NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY); + + mService.buzzBeepBlinkLocked(child); + + verifyNeverLights(); + assertFalse(child.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryLightsSummary() { + NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_SUMMARY); + summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; + + mService.buzzBeepBlinkLocked(summary); + + verifyLights(); + // summaries should never count for interruptiveness counts + assertFalse(summary.isInterruptive()); + } + + @Test + public void testGroupAlertSummaryLightsNonGroupChild() { + NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_SUMMARY); + + mService.buzzBeepBlinkLocked(nonGroup); + + verifyLights(); + assertTrue(nonGroup.isInterruptive()); + } + + @Test + public void testGroupAlertChildNoLightsSummary() { + NotificationRecord summary = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN); + summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY; + + mService.buzzBeepBlinkLocked(summary); + + verifyNeverLights(); + assertFalse(summary.isInterruptive()); + } + + @Test + public void testGroupAlertChildLightsChild() { + NotificationRecord child = getLightsNotificationRecord("a", GROUP_ALERT_CHILDREN); + + mService.buzzBeepBlinkLocked(child); + + verifyLights(); + assertTrue(child.isInterruptive()); + } + + @Test + public void testGroupAlertChildLightsNonGroupSummary() { + NotificationRecord nonGroup = getLightsNotificationRecord(null, GROUP_ALERT_CHILDREN); + + mService.buzzBeepBlinkLocked(nonGroup); + + verifyLights(); + assertTrue(nonGroup.isInterruptive()); + } + + @Test + public void testGroupAlertAllLightsGroup() { + NotificationRecord group = getLightsNotificationRecord("a", GROUP_ALERT_ALL); + + mService.buzzBeepBlinkLocked(group); + + verifyLights(); + assertTrue(group.isInterruptive()); + } + static class VibrateRepeatMatcher implements ArgumentMatcher<VibrationEffect> { private final int mRepeatIndex; diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java index 3c4e333b6be9..82e0fbe0e400 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/PinnedSliceStateTest.java @@ -1,16 +1,16 @@ package com.android.server.slice; +import static android.testing.TestableContentResolver.UNSTABLE; + import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -71,11 +71,12 @@ public class PinnedSliceStateTest extends UiServiceTestCase { mSliceService = mock(SliceManagerService.class); when(mSliceService.getContext()).thenReturn(mContext); when(mSliceService.getLock()).thenReturn(new Object()); - when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper())); + when(mSliceService.getHandler()).thenReturn( + new Handler(TestableLooper.get(this).getLooper())); mContentProvider = mock(ContentProvider.class); mIContentProvider = mock(IContentProvider.class); when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider); - mContext.getContentResolver().addProvider(AUTH, mContentProvider); + mContext.getContentResolver().addProvider(AUTH, mContentProvider, UNSTABLE); mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg"); } diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java index 0dce7382290c..4b7e21f2d536 100644 --- a/services/usage/java/com/android/server/usage/IntervalStats.java +++ b/services/usage/java/com/android/server/usage/IntervalStats.java @@ -27,7 +27,9 @@ import android.util.ArraySet; import java.util.List; -class IntervalStats { +import com.android.internal.annotations.VisibleForTesting; + +public class IntervalStats { public long beginTime; public long endTime; public long lastTimeSaved; @@ -149,7 +151,11 @@ class IntervalStats { && eventType != UsageEvents.Event.STANDBY_BUCKET_CHANGED; } - void update(String packageName, long timeStamp, int eventType) { + /** + * @hide + */ + @VisibleForTesting + public void update(String packageName, long timeStamp, int eventType) { UsageStats usageStats = getOrCreateUsageStats(packageName); // TODO(adamlesinski): Ensure that we recover from incorrect event sequences diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java index 970546976336..5ab5dc223d9e 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java +++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java @@ -42,7 +42,7 @@ import java.util.List; /** * Provides an interface to query for UsageStat data from an XML database. */ -class UsageStatsDatabase { +public class UsageStatsDatabase { private static final int CURRENT_VERSION = 3; // Current version of the backup schema @@ -369,7 +369,7 @@ class UsageStatsDatabase { /** * Figures out what to extract from the given IntervalStats object. */ - interface StatCombiner<T> { + public interface StatCombiner<T> { /** * Implementations should extract interesting from <code>stats</code> and add it diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 3e97c8f40bf8..468c8fa9e30c 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -854,6 +854,8 @@ public abstract class Connection extends Conferenceable { private final OutputStreamWriter mPipeToInCall; private final ParcelFileDescriptor mFdFromInCall; private final ParcelFileDescriptor mFdToInCall; + + private final FileInputStream mFromInCallFileInputStream; private char[] mReadBuffer = new char[READ_BUFFER_SIZE]; /** @@ -862,11 +864,11 @@ public abstract class Connection extends Conferenceable { public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) { mFdFromInCall = fromInCall; mFdToInCall = toInCall; + mFromInCallFileInputStream = new FileInputStream(fromInCall.getFileDescriptor()); // Wrap the FileInputStream in a Channel so that it's interruptible. mPipeFromInCall = new InputStreamReader( - Channels.newInputStream(Channels.newChannel( - new FileInputStream(fromInCall.getFileDescriptor())))); + Channels.newInputStream(Channels.newChannel(mFromInCallFileInputStream))); mPipeToInCall = new OutputStreamWriter( new FileOutputStream(toInCall.getFileDescriptor())); } @@ -914,7 +916,7 @@ public abstract class Connection extends Conferenceable { * not entered any new text yet. */ public String readImmediately() throws IOException { - if (mPipeFromInCall.ready()) { + if (mFromInCallFileInputStream.available() > 0) { return read(); } else { return null; diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 7e86966e2c1b..2b6928e2e4f1 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -121,6 +121,8 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Get reference signal received quality + * + * @return the RSRQ if available or Integer.MAX_VALUE if unavailable. */ public int getRsrq() { return mRsrq; @@ -128,13 +130,17 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Get reference signal signal-to-noise ratio + * + * @return the RSSNR if available or Integer.MAX_VALUE if unavailable. */ public int getRssnr() { return mRssnr; } /** - * Get reference signal received power + * Get reference signal received power in dBm + * + * @return the RSRP of the measured cell. */ public int getRsrp() { return mRsrp; @@ -142,13 +148,17 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Get channel quality indicator + * + * @return the CQI if available or Integer.MAX_VALUE if unavailable. */ public int getCqi() { return mCqi; } /** - * Get signal strength as dBm + * Get signal strength in dBm + * + * @return the RSRP of the measured cell. */ @Override public int getDbm() { @@ -175,7 +185,8 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P * Get the timing advance value for LTE, as a value in range of 0..1282. * Integer.MAX_VALUE is reported when there is no active RRC * connection. Refer to 3GPP 36.213 Sec 4.2.3 - * @return the LTE timing advance, if available. + * + * @return the LTE timing advance if available or Integer.MAX_VALUE if unavailable. */ public int getTimingAdvance() { return mTimingAdvance; diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 936505ca407d..d76e39b83801 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -33,9 +33,9 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.DisplayMetrics; +import android.util.Log; import java.util.Arrays; -import java.util.ArrayList; import java.util.List; /** @@ -105,12 +105,12 @@ public class SubscriptionInfo implements Parcelable { /** * Mobile Country Code */ - private int mMcc; + private String mMcc; /** * Mobile Network Code */ - private int mMnc; + private String mMnc; /** * ISO Country code for the subscription's provider @@ -138,11 +138,11 @@ public class SubscriptionInfo implements Parcelable { * @hide */ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, - CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, - Bitmap icon, int mcc, int mnc, String countryIso) { + CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, + Bitmap icon, String mcc, String mnc, String countryIso) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, - roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */, - null /* accessRules */, null /* accessRules */); + roaming, icon, mcc, mnc, countryIso, false /* isEmbedded */, + null /* accessRules */, null /* accessRules */); } /** @@ -150,7 +150,7 @@ public class SubscriptionInfo implements Parcelable { */ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, - Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded, + Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules) { this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number, roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, null /* cardId */); @@ -161,7 +161,7 @@ public class SubscriptionInfo implements Parcelable { */ public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName, CharSequence carrierName, int nameSource, int iconTint, String number, int roaming, - Bitmap icon, int mcc, int mnc, String countryIso, boolean isEmbedded, + Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded, @Nullable UiccAccessRule[] accessRules, String cardId) { this.mId = id; this.mIccId = iccId; @@ -316,15 +316,43 @@ public class SubscriptionInfo implements Parcelable { /** * @return the MCC. + * @deprecated Use {@link #getMccString()} instead. */ + @Deprecated public int getMcc() { - return this.mMcc; + try { + return this.mMcc == null ? 0 : Integer.valueOf(this.mMcc); + } catch (NumberFormatException e) { + Log.w(SubscriptionInfo.class.getSimpleName(), "MCC string is not a number"); + return 0; + } } /** * @return the MNC. + * @deprecated Use {@link #getMncString()} instead. */ + @Deprecated public int getMnc() { + try { + return this.mMnc == null ? 0 : Integer.valueOf(this.mMnc); + } catch (NumberFormatException e) { + Log.w(SubscriptionInfo.class.getSimpleName(), "MNC string is not a number"); + return 0; + } + } + + /** + * @return The MCC, as a string. + */ + public String getMccString() { + return this.mMcc; + } + + /** + * @return The MNC, as a string. + */ + public String getMncString() { return this.mMnc; } @@ -425,8 +453,8 @@ public class SubscriptionInfo implements Parcelable { int iconTint = source.readInt(); String number = source.readString(); int dataRoaming = source.readInt(); - int mcc = source.readInt(); - int mnc = source.readInt(); + String mcc = source.readString(); + String mnc = source.readString(); String countryIso = source.readString(); Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source); boolean isEmbedded = source.readBoolean(); @@ -455,8 +483,8 @@ public class SubscriptionInfo implements Parcelable { dest.writeInt(mIconTint); dest.writeString(mNumber); dest.writeInt(mDataRoaming); - dest.writeInt(mMcc); - dest.writeInt(mMnc); + dest.writeString(mMcc); + dest.writeString(mMnc); dest.writeString(mCountryIso); mIconBitmap.writeToParcel(dest, flags); dest.writeBoolean(mIsEmbedded); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index ece646ca7b2c..17e7c49f6289 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -253,6 +253,20 @@ public class SubscriptionManager { public static final int SIM_PROVISIONED = 0; /** + * TelephonyProvider column name for the MCC associated with a SIM, stored as a string. + * <P>Type: TEXT (String)</P> + * @hide + */ + public static final String MCC_STRING = "mcc_string"; + + /** + * TelephonyProvider column name for the MNC associated with a SIM, stored as a string. + * <P>Type: TEXT (String)</P> + * @hide + */ + public static final String MNC_STRING = "mnc_string"; + + /** * TelephonyProvider column name for the MCC associated with a SIM. * <P>Type: INTEGER (int)</P> * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 6e261dd98cac..9e23c5cbbecb 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1312,6 +1312,33 @@ public class TelephonyManager { } /** + * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not + * available. + */ + public String getTypeAllocationCode() { + return getTypeAllocationCode(getSlotIndex()); + } + + /** + * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not + * available. + * + * @param slotIndex of which Type Allocation Code is returned + */ + public String getTypeAllocationCode(int slotIndex) { + ITelephony telephony = getITelephony(); + if (telephony == null) return null; + + try { + return telephony.getTypeAllocationCodeForSlot(slotIndex); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + } + + /** * Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available. * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} @@ -1347,6 +1374,33 @@ public class TelephonyManager { } /** + * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not + * available. + */ + public String getManufacturerCode() { + return getManufacturerCode(getSlotIndex()); + } + + /** + * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not + * available. + * + * @param slotIndex of which Type Allocation Code is returned + */ + public String getManufacturerCode(int slotIndex) { + ITelephony telephony = getITelephony(); + if (telephony == null) return null; + + try { + return telephony.getManufacturerCodeForSlot(slotIndex); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + } + + /** * Returns the Network Access Identifier (NAI). Return null if NAI is not available. * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java index d03c7e1da5fa..e158fa84e34e 100644 --- a/telephony/java/android/telephony/ims/ImsExternalCallState.java +++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java @@ -87,6 +87,7 @@ public final class ImsExternalCallState implements Parcelable { mCallId = in.readInt(); ClassLoader classLoader = ImsExternalCallState.class.getClassLoader(); mAddress = in.readParcelable(classLoader); + mLocalAddress = in.readParcelable(classLoader); mIsPullable = (in.readInt() != 0); mCallState = in.readInt(); mCallType = in.readInt(); @@ -103,6 +104,7 @@ public final class ImsExternalCallState implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeInt(mCallId); out.writeParcelable(mAddress, 0); + out.writeParcelable(mLocalAddress, 0); out.writeInt(mIsPullable ? 1 : 0); out.writeInt(mCallState); out.writeInt(mCallType); @@ -131,6 +133,11 @@ public final class ImsExternalCallState implements Parcelable { return mAddress; } + /** @hide */ + public Uri getLocalAddress() { + return mLocalAddress; + } + public boolean isCallPullable() { return mIsPullable; } @@ -151,6 +158,7 @@ public final class ImsExternalCallState implements Parcelable { public String toString() { return "ImsExternalCallState { mCallId = " + mCallId + ", mAddress = " + Log.pii(mAddress) + + ", mLocalAddress = " + Log.pii(mLocalAddress) + ", mIsPullable = " + mIsPullable + ", mCallState = " + mCallState + ", mCallType = " + mCallType + diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 84a18b453941..d850fbc471ab 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1195,6 +1195,13 @@ interface ITelephony { String getImeiForSlot(int slotIndex, String callingPackage); /** + * Returns the Type Allocation Code from the IMEI for the given slot. + * + * @param slotIndex - Which slot to retrieve the Type Allocation Code from. + */ + String getTypeAllocationCodeForSlot(int slotIndex); + + /** * Returns the MEID for the given slot. * * @param slotIndex - device slot. @@ -1205,6 +1212,13 @@ interface ITelephony { String getMeidForSlot(int slotIndex, String callingPackage); /** + * Returns the Manufacturer Code from the MEID for the given slot. + * + * @param slotIndex - Which slot to retrieve the Manufacturer Code from. + */ + String getManufacturerCodeForSlot(int slotIndex); + + /** * Returns the device software version. * * @param slotIndex - device slot. diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java index b763c78207de..b4b5ca7161fc 100644 --- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java +++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java @@ -30,6 +30,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; +import android.os.Trace; import java.util.ArrayList; import java.util.Collections; @@ -42,6 +43,7 @@ class TouchLatencyView extends View implements View.OnTouchListener { public TouchLatencyView(Context context, AttributeSet attrs) { super(context, attrs); + Trace.beginSection("TouchLatencyView constructor"); setOnTouchListener(this); setWillNotDraw(false); mBluePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -63,48 +65,56 @@ class TouchLatencyView extends View implements View.OnTouchListener { mBallY = 100.0f; mVelocityX = 7.0f; mVelocityY = 7.0f; + Trace.endSection(); } @Override public boolean onTouch(View view, MotionEvent event) { + Trace.beginSection("TouchLatencyView onTouch"); int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) { mTouching = true; invalidate(); + + mTouchX = event.getX(); + mTouchY = event.getY(); } else if (action == MotionEvent.ACTION_UP) { mTouching = false; invalidate(); - return true; - } else { - return true; } - mTouchX = event.getX(); - mTouchY = event.getY(); + Trace.endSection(); return true; } private void drawTouch(Canvas canvas) { - if (!mTouching) { - Log.d(LOG_TAG, "Filling background"); - canvas.drawColor(BACKGROUND_COLOR); - return; - } + Trace.beginSection("TouchLatencyView drawTouch"); - float deltaX = (mTouchX - mLastDrawnX); - float deltaY = (mTouchY - mLastDrawnY); - float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f; + try { + if (!mTouching) { + Log.d(LOG_TAG, "Filling background"); + canvas.drawColor(BACKGROUND_COLOR); + return; + } - mLastDrawnX = mTouchX; - mLastDrawnY = mTouchY; + float deltaX = (mTouchX - mLastDrawnX); + float deltaY = (mTouchY - mLastDrawnY); + float scaleFactor = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY) * 1.5f; - canvas.drawColor(BACKGROUND_COLOR); - canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint); - canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint); - canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint); - canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint); + mLastDrawnX = mTouchX; + mLastDrawnY = mTouchY; + + canvas.drawColor(BACKGROUND_COLOR); + canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 3 * scaleFactor, mRedPaint); + canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + 2 * scaleFactor, mYellowPaint); + canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS + scaleFactor, mGreenPaint); + canvas.drawCircle(mTouchX, mTouchY, INNER_RADIUS, mBluePaint); + } finally { + Trace.endSection(); + } } private void drawBall(Canvas canvas) { + Trace.beginSection("TouchLatencyView drawBall"); int width = canvas.getWidth(); int height = canvas.getHeight(); @@ -141,25 +151,29 @@ class TouchLatencyView extends View implements View.OnTouchListener { canvas.drawColor(BACKGROUND_COLOR); canvas.drawOval(left, top, right, bottom, mYellowPaint); invalidate(); + Trace.endSection(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); - + Trace.beginSection("TouchLatencyView onDraw"); if (mMode == 0) { drawTouch(canvas); } else { drawBall(canvas); } + Trace.endSection(); } public void changeMode(MenuItem item) { + Trace.beginSection("TouchLatencyView changeMode"); final int NUM_MODES = 2; final String modes[] = {"Touch", "Ball"}; mMode = (mMode + 1) % NUM_MODES; invalidate(); item.setTitle(modes[mMode]); + Trace.endSection(); } private Paint mBluePaint, mGreenPaint, mYellowPaint, mRedPaint; @@ -178,21 +192,26 @@ public class TouchLatencyActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Trace.beginSection("TouchLatencyActivity onCreate"); setContentView(R.layout.activity_touch_latency); mTouchView = findViewById(R.id.canvasView); + Trace.endSection(); } @Override public boolean onCreateOptionsMenu(Menu menu) { + Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu"); // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_touch_latency, menu); + Trace.endSection(); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { + Trace.beginSection("TouchLatencyActivity onOptionsItemSelected"); // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. @@ -203,6 +222,7 @@ public class TouchLatencyActivity extends Activity { mTouchView.changeMode(item); } + Trace.endSection(); return super.onOptionsItemSelected(item); } diff --git a/tests/UsageStatsPerfTests/Android.mk b/tests/UsageStatsPerfTests/Android.mk new file mode 100644 index 000000000000..cd29b51e5a24 --- /dev/null +++ b/tests/UsageStatsPerfTests/Android.mk @@ -0,0 +1,34 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := \ + $(call all-java-files-under, src) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + apct-perftests-utils \ + services.usage + +LOCAL_PACKAGE_NAME := UsageStatsPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true + +# For android.permission.FORCE_STOP_PACKAGES permission +LOCAL_CERTIFICATE := platform + +include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsPerfTests/AndroidManifest.xml b/tests/UsageStatsPerfTests/AndroidManifest.xml new file mode 100644 index 000000000000..596a79cd8948 --- /dev/null +++ b/tests/UsageStatsPerfTests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.frameworks.perftests.usage"> + <uses-sdk + android:minSdkVersion="21" /> + <uses-permission android:name="android.permission.DUMP" /> + <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.frameworks.perftests.usage"/> +</manifest> diff --git a/tests/UsageStatsPerfTests/AndroidTest.xml b/tests/UsageStatsPerfTests/AndroidTest.xml new file mode 100644 index 000000000000..c9b51dc5ba07 --- /dev/null +++ b/tests/UsageStatsPerfTests/AndroidTest.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Runs UsageStats Performance Tests"> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> + <option name="test-file-name" value="UsageStatsPerfTests.apk"/> + <option name="cleanup-apks" value="true"/> + </target_preparer> + + <option name="test-suite-tag" value="apct"/> + <option name="test-tag" value="UsageStatsPerfTests"/> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.frameworks.perftests.usage"/> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java new file mode 100644 index 000000000000..8467bee819cb --- /dev/null +++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.frameworks.perftests.usage.tests; + +import static junit.framework.Assert.assertEquals; + +import com.android.server.usage.UsageStatsDatabase; +import com.android.server.usage.UsageStatsDatabase.StatCombiner; +import com.android.server.usage.IntervalStats; + +import android.app.usage.EventList; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.os.SystemClock; +import android.perftests.utils.ManualBenchmarkState; +import android.perftests.utils.PerfManualStatusReporter; +import android.support.test.filters.LargeTest; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class UsageStatsDatabasePerfTest { + protected static Context sContext; + private static UsageStatsDatabase sUsageStatsDatabase; + private static File mTestDir; + + // Represents how many apps might have used in a day by a user with a few apps + final static int FEW_PKGS = 10; + // Represent how many apps might have used in a day by a user with many apps + final static int MANY_PKGS = 50; + // Represents how many usage events per app a device might have with light usage + final static int LIGHT_USE = 10; + // Represents how many usage events per app a device might have with heavy usage + final static int HEAVY_USE = 50; + + private static final StatCombiner<UsageEvents.Event> sUsageStatsCombiner = + new StatCombiner<UsageEvents.Event>() { + @Override + public void combine(IntervalStats stats, boolean mutable, + List<UsageEvents.Event> accResult) { + final int size = stats.events.size(); + for (int i = 0; i < size; i++) { + accResult.add(stats.events.get(i)); + } + } + }; + + + @Rule + public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter(); + + @BeforeClass + public static void setUpOnce() { + sContext = InstrumentationRegistry.getTargetContext(); + mTestDir = new File(sContext.getFilesDir(), "UsageStatsDatabasePerfTest"); + sUsageStatsDatabase = new UsageStatsDatabase(mTestDir); + sUsageStatsDatabase.init(1); + } + + private static void populateIntervalStats(IntervalStats intervalStats, int packageCount, + int eventsPerPackage) { + if (intervalStats.events == null) { + intervalStats.events = new EventList(); + } + for (int pkg = 0; pkg < packageCount; pkg++) { + UsageEvents.Event event = new UsageEvents.Event(); + event.mPackage = "fake.package.name" + pkg; + event.mTimeStamp = 1; + event.mEventType = UsageEvents.Event.MOVE_TO_FOREGROUND; + for (int evt = 0; evt < eventsPerPackage; evt++) { + intervalStats.events.insert(event); + intervalStats.update(event.mPackage, event.mTimeStamp, event.mEventType); + } + } + } + + private static void clearUsageStatsFiles() { + File[] intervalDirs = mTestDir.listFiles(); + for (File intervalDir : intervalDirs) { + if (intervalDir.isDirectory()) { + File[] usageFiles = intervalDir.listFiles(); + for (File f : usageFiles) { + f.delete(); + } + } + } + } + + private void runQueryUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException { + final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState(); + IntervalStats intervalStats = new IntervalStats(); + populateIntervalStats(intervalStats, packageCount, eventsPerPackage); + sUsageStatsDatabase.putUsageStats(0, intervalStats); + long elapsedTimeNs = 0; + while (benchmarkState.keepRunning(elapsedTimeNs)) { + final long startTime = SystemClock.elapsedRealtimeNanos(); + List<UsageEvents.Event> temp = sUsageStatsDatabase.queryUsageStats( + UsageStatsManager.INTERVAL_DAILY, 0, 2, sUsageStatsCombiner); + final long endTime = SystemClock.elapsedRealtimeNanos(); + elapsedTimeNs = endTime - startTime; + assertEquals(packageCount * eventsPerPackage, temp.size()); + } + } + + private void runPutUsageStatsTest(int packageCount, int eventsPerPackage) throws IOException { + final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState(); + IntervalStats intervalStats = new IntervalStats(); + populateIntervalStats(intervalStats, packageCount, eventsPerPackage); + long elapsedTimeNs = 0; + while (benchmarkState.keepRunning(elapsedTimeNs)) { + final long startTime = SystemClock.elapsedRealtimeNanos(); + sUsageStatsDatabase.putUsageStats(0, intervalStats); + final long endTime = SystemClock.elapsedRealtimeNanos(); + elapsedTimeNs = endTime - startTime; + clearUsageStatsFiles(); + } + } + + @Test + public void testQueryUsageStats_FewPkgsLightUse() throws IOException { + runQueryUsageStatsTest(FEW_PKGS, LIGHT_USE); + } + + @Test + public void testPutUsageStats_FewPkgsLightUse() throws IOException { + runPutUsageStatsTest(FEW_PKGS, LIGHT_USE); + } + + @Test + public void testQueryUsageStats_FewPkgsHeavyUse() throws IOException { + runQueryUsageStatsTest(FEW_PKGS, HEAVY_USE); + } + + @Test + public void testPutUsageStats_FewPkgsHeavyUse() throws IOException { + runPutUsageStatsTest(FEW_PKGS, HEAVY_USE); + } + + @Test + public void testQueryUsageStats_ManyPkgsLightUse() throws IOException { + runQueryUsageStatsTest(MANY_PKGS, LIGHT_USE); + } + + @Test + public void testPutUsageStats_ManyPkgsLightUse() throws IOException { + runPutUsageStatsTest(MANY_PKGS, LIGHT_USE); + } + + @Test + public void testQueryUsageStats_ManyPkgsHeavyUse() throws IOException { + runQueryUsageStatsTest(MANY_PKGS, HEAVY_USE); + } + + @Test + public void testPutUsageStats_ManyPkgsHeavyUse() throws IOException { + runPutUsageStatsTest(MANY_PKGS, HEAVY_USE); + } +} diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java index 0850916ccbe5..a0afef8fcda3 100644 --- a/tests/testables/src/android/testing/TestableContentResolver.java +++ b/tests/testables/src/android/testing/TestableContentResolver.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.IContentProvider; import android.database.ContentObserver; import android.net.Uri; +import android.util.ArrayMap; import android.util.ArraySet; import com.google.android.collect.Maps; @@ -35,7 +36,11 @@ import java.util.Map; */ public class TestableContentResolver extends ContentResolver { - private final Map<String, ContentProvider> mProviders = Maps.newHashMap(); + public static final int STABLE = 1; + public static final int UNSTABLE = 2; + + private final Map<String, ContentProvider> mProviders = new ArrayMap<>(); + private final Map<String, ContentProvider> mUnstableProviders = new ArrayMap<>(); private final ContentResolver mParent; private final ArraySet<ContentProvider> mInUse = new ArraySet<>(); private boolean mFallbackToExisting; @@ -62,7 +67,23 @@ public class TestableContentResolver extends ContentResolver { * subclasses, or null. */ public void addProvider(String name, ContentProvider provider) { - mProviders.put(name, provider); + addProvider(name, provider, STABLE | UNSTABLE); + } + + /** + * Adds access to a provider based on its authority + * + * @param name The authority name associated with the provider. + * @param provider An instance of {@link android.content.ContentProvider} or one of its + * subclasses, or null. + */ + public void addProvider(String name, ContentProvider provider, int flags) { + if ((flags & STABLE) != 0) { + mProviders.put(name, provider); + } + if ((flags & UNSTABLE) != 0) { + mUnstableProviders.put(name, provider); + } } @Override @@ -98,7 +119,7 @@ public class TestableContentResolver extends ContentResolver { @Override protected IContentProvider acquireUnstableProvider(Context c, String name) { - final ContentProvider provider = mProviders.get(name); + final ContentProvider provider = mUnstableProviders.get(name); if (provider != null) { return provider.getIContentProvider(); } else { @@ -128,7 +149,8 @@ public class TestableContentResolver extends ContentResolver { @Override public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { if (!mFallbackToExisting) return; - if (!mProviders.containsKey(uri.getAuthority())) { + if (!mProviders.containsKey(uri.getAuthority()) + && !mUnstableProviders.containsKey(uri.getAuthority())) { super.notifyChange(uri, observer, syncToNetwork); } } diff --git a/tests/testables/tests/src/android/testing/TestableContentResolverTest.java b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java new file mode 100644 index 000000000000..71afda0748c4 --- /dev/null +++ b/tests/testables/tests/src/android/testing/TestableContentResolverTest.java @@ -0,0 +1,61 @@ +package android.testing; + +import android.content.ContentProvider; +import android.content.IContentProvider; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class TestableContentResolverTest { + + @Rule + public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext()); + private TestableContentResolver mContentResolver; + + @Before + public void setup() { + mContentResolver = new TestableContentResolver(mContext); + mContentResolver.setFallbackToExisting(false); + } + + @Test + public void testDefaultContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider); + + Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test")); + Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test")); + } + + @Test + public void testStableContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider, TestableContentResolver.STABLE); + + Assert.assertEquals(iprovider, mContentResolver.acquireProvider(mContext, "test")); + Assert.assertNull(mContentResolver.acquireUnstableProvider(mContext, "test")); + } + + @Test + public void testUnstableContentProvider() { + ContentProvider provider = Mockito.mock(ContentProvider.class); + IContentProvider iprovider = Mockito.mock(IContentProvider.class); + Mockito.when(provider.getIContentProvider()).thenReturn(iprovider); + mContentResolver.addProvider("test", provider, TestableContentResolver.UNSTABLE); + + Assert.assertEquals(iprovider, mContentResolver.acquireUnstableProvider(mContext, "test")); + Assert.assertNull(mContentResolver.acquireProvider(mContext, "test")); + } +} diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp index b37e1fbd9693..8eabd3225d87 100644 --- a/tools/aapt2/StringPool.cpp +++ b/tools/aapt2/StringPool.cpp @@ -367,7 +367,7 @@ const std::string kStringTooLarge = "STRING_TOO_LARGE"; static bool EncodeString(const std::string& str, const bool utf8, BigBuffer* out, IDiagnostics* diag) { if (utf8) { - const std::string& encoded = str; + const std::string& encoded = util::Utf8ToModifiedUtf8(str); const ssize_t utf16_length = utf8_to_utf16_length( reinterpret_cast<const uint8_t*>(encoded.data()), encoded.size()); CHECK(utf16_length >= 0); diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp index 4b3afe2bb962..0778564ee079 100644 --- a/tools/aapt2/StringPool_test.cpp +++ b/tools/aapt2/StringPool_test.cpp @@ -303,6 +303,25 @@ TEST(StringPoolTest, Flatten) { } } +TEST(StringPoolTest, FlattenModifiedUTF8) { + using namespace android; // For NO_ERROR on Windows. + StdErrDiagnostics diag; + StringPool pool; + StringPool::Ref ref_a = pool.MakeRef("\xF0\x90\x90\x80"); // 𐐀 (U+10400) + StringPool::Ref ref_b = pool.MakeRef("foo \xF0\x90\x90\xB7 bar"); // 𐐷 (U+10437) + StringPool::Ref ref_c = pool.MakeRef("\xF0\x90\x90\x80\xF0\x90\x90\xB7"); + + BigBuffer buffer(1024); + StringPool::FlattenUtf8(&buffer, pool, &diag); + std::unique_ptr<uint8_t[]> data = util::Copy(buffer); + + // Check that the 4 byte utf-8 codepoint is encoded using 2 3 byte surrogate pairs + ResStringPool test; + ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR); + EXPECT_THAT(util::GetString(test, 0), Eq("\xED\xA0\x81\xED\xB0\x80")); + EXPECT_THAT(util::GetString(test, 1), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar")); + EXPECT_THAT(util::GetString(test, 2), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7")); +} TEST(StringPoolTest, MaxEncodingLength) { StdErrDiagnostics diag; diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index d1c9ca1644d9..9bef54e590c9 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -297,6 +297,53 @@ bool VerifyJavaStringFormat(const StringPiece& str) { return true; } +std::string Utf8ToModifiedUtf8(const std::string& utf8) { + // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode + // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format + // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8 + // codepoints replaced with 2 3 byte surrogate pairs + size_t modified_size = 0; + const size_t size = utf8.size(); + for (size_t i = 0; i < size; i++) { + if (((uint8_t) utf8[i] >> 4) == 0xF) { + modified_size += 6; + i += 3; + } else { + modified_size++; + } + } + + // Early out if no 4 byte codepoints are found + if (size == modified_size) { + return utf8; + } + + std::string output; + output.reserve(modified_size); + for (size_t i = 0; i < size; i++) { + if (((uint8_t) utf8[i] >> 4) == 0xF) { + auto codepoint = (char32_t) utf32_from_utf8_at(utf8.data(), size, i, nullptr); + + // Calculate the high and low surrogates as UTF-16 would + char32_t high = ((codepoint - 0x10000) / 0x400) + 0xD800; + char32_t low = ((codepoint - 0x10000) % 0x400) + 0xDC00; + + // Encode each surrogate in UTF-8 + output.push_back((char) (0xE4 | ((high >> 12) & 0xF))); + output.push_back((char) (0x80 | ((high >> 6) & 0x3F))); + output.push_back((char) (0x80 | (high & 0x3F))); + output.push_back((char) (0xE4 | ((low >> 12) & 0xF))); + output.push_back((char) (0x80 | ((low >> 6) & 0x3F))); + output.push_back((char) (0x80 | (low & 0x3F))); + i += 3; + } else { + output.push_back(utf8[i]); + } + } + + return output; +} + std::u16string Utf8ToUtf16(const StringPiece& utf8) { ssize_t utf16_length = utf8_to_utf16_length( reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length()); diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index 0eb35d18c06e..36b733376e6f 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -197,6 +197,9 @@ inline StringBuilder::operator bool() const { return error_.empty(); } +// Converts a UTF8 string into Modified UTF8 +std::string Utf8ToModifiedUtf8(const std::string& utf8); + // Converts a UTF8 string to a UTF16 string. std::u16string Utf8ToUtf16(const android::StringPiece& utf8); std::string Utf16ToUtf8(const android::StringPiece16& utf16); diff --git a/wifi/OWNERS b/wifi/OWNERS index 0efa4646a80a..0601047d7caa 100644 --- a/wifi/OWNERS +++ b/wifi/OWNERS @@ -1,5 +1,6 @@ set noparent etancohen@google.com +mplass@google.com +rpius@google.com satk@google.com -silberst@google.com |