Merge "Fixes more null pointer exceptions caused by ag/9382746"
diff --git a/api/current.txt b/api/current.txt
index 4174b6a..b176675 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -40856,7 +40856,7 @@
field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
field public static final String EXTRA_NAME = "name";
field public static final String EXTRA_PKCS12 = "PKCS12";
- field public static final String KEY_ALIAS_SELECTION_DENIED = "alias-selection-denied-ef829e15-210a-409d-96c9-ee684fc41972";
+ field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
}
public interface KeyChainAliasCallback {
diff --git a/api/system-current.txt b/api/system-current.txt
index 46413d3..6e35200 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -172,6 +172,7 @@
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
+ field public static final String RESTORE_RUNTIME_PERMISSIONS = "android.permission.RESTORE_RUNTIME_PERMISSIONS";
field public static final String RESTRICTED_VR_ACCESS = "android.permission.RESTRICTED_VR_ACCESS";
field public static final String RETRIEVE_WINDOW_CONTENT = "android.permission.RETRIEVE_WINDOW_CONTENT";
field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES";
@@ -5701,7 +5702,10 @@
package android.permission {
public final class PermissionControllerManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.RESTORE_RUNTIME_PERMISSIONS}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
@@ -5715,17 +5719,19 @@
public abstract class PermissionControllerService extends android.app.Service {
ctor public PermissionControllerService();
+ method @BinderThread public void onApplyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull public final android.os.IBinder onBind(android.content.Intent);
method @BinderThread public abstract void onCountPermissionApps(@NonNull java.util.List<java.lang.String>, int, @NonNull java.util.function.IntConsumer);
method @BinderThread public abstract void onGetAppPermissions(@NonNull String, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionPresentationInfo>>);
method @BinderThread public abstract void onGetPermissionUsages(boolean, long, @NonNull java.util.function.Consumer<java.util.List<android.permission.RuntimePermissionUsageInfo>>);
method @BinderThread public abstract void onGetRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.OutputStream, @NonNull Runnable);
method @BinderThread public abstract void onGrantOrUpgradeDefaultRuntimePermissions(@NonNull Runnable);
- method @BinderThread public abstract void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
+ method @Deprecated @BinderThread public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @Deprecated @BinderThread public void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String, @NonNull Runnable);
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
method @BinderThread public void onUpdateUserSensitive();
field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 9b85b96..2c7e44d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2253,8 +2253,11 @@
package android.permission {
public final class PermissionControllerManager {
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void applyStagedRuntimePermissionBackup(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getAppPermissions(@NonNull String, @NonNull android.permission.PermissionControllerManager.OnGetAppPermissionResultCallback, @Nullable android.os.Handler);
+ method @RequiresPermission("android.permission.GET_RUNTIME_PERMISSIONS") public void getRuntimePermissionBackup(@NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<byte[]>);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public void revokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull java.util.concurrent.Executor, @NonNull android.permission.PermissionControllerManager.OnRevokeRuntimePermissionsCallback);
+ method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.RESTORE_RUNTIME_PERMISSIONS"}) public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[], @NonNull android.os.UserHandle);
field public static final int COUNT_ONLY_WHEN_GRANTED = 1; // 0x1
field public static final int COUNT_WHEN_SYSTEM = 2; // 0x2
field public static final int REASON_INSTALLER_POLICY_VIOLATION = 2; // 0x2
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 654b0f7..26c1ec1 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -31,8 +31,8 @@
void revokeRuntimePermissions(in Bundle request, boolean doDryRun, int reason,
String callerPackageName, in AndroidFuture callback);
void getRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
- void restoreRuntimePermissionBackup(in UserHandle user, in ParcelFileDescriptor pipe);
- void restoreDelayedRuntimePermissionBackup(String packageName, in UserHandle user,
+ void stageAndApplyRuntimePermissionsBackup(in UserHandle user, in ParcelFileDescriptor pipe);
+ void applyStagedRuntimePermissionBackup(String packageName, in UserHandle user,
in AndroidFuture callback);
void getAppPermissions(String packageName, in AndroidFuture callback);
void revokeRuntimePermission(String packageName, String permissionName);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 923d9f8..421e29e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -62,6 +62,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -139,20 +140,6 @@
}
/**
- * Callback for delivering the result of {@link #getRuntimePermissionBackup}.
- *
- * @hide
- */
- public interface OnGetRuntimePermissionBackupCallback {
- /**
- * The result for {@link #getRuntimePermissionBackup}.
- *
- * @param backup The backup file
- */
- void onGetRuntimePermissionsBackup(@NonNull byte[] backup);
- }
-
- /**
* Callback for delivering the result of {@link #getAppPermissions}.
*
* @hide
@@ -246,6 +233,24 @@
}
/**
+ * Throw a {@link SecurityException} if not at least one of the permissions is granted.
+ *
+ * @param requiredPermissions A list of permissions. Any of of them if sufficient to pass the
+ * check
+ */
+ private void enforceSomePermissionsGrantedToSelf(@NonNull String... requiredPermissions) {
+ for (String requiredPermission : requiredPermissions) {
+ if (mContext.checkSelfPermission(requiredPermission)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ throw new SecurityException("At lest one of the following permissions is required: "
+ + Arrays.toString(requiredPermissions));
+ }
+
+ /**
* Revoke a set of runtime permissions for various apps.
*
* @param request The permissions to revoke as {@code Map<packageName, List<permission>>}
@@ -268,11 +273,7 @@
}
// Check required permission to fail immediately instead of inside the oneway binder call
- if (mContext.checkSelfPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
- + " required");
- }
+ enforceSomePermissionsGrantedToSelf(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
mRemoteService.postAsync(service -> {
Bundle bundledizedRequest = new Bundle();
@@ -358,46 +359,61 @@
*
* @param user The user to be backed up
* @param executor Executor on which to invoke the callback
- * @param callback Callback to receive the result
- *
- * @hide
+ * @param callback Callback to receive the result. The resulting backup-file is opaque and no
+ * guarantees are made other than that the file can be send to
+ * {@link #restoreRuntimePermissionBackup} in this and future versions of
+ * Android.
*/
@RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
public void getRuntimePermissionBackup(@NonNull UserHandle user,
@NonNull @CallbackExecutor Executor executor,
- @NonNull OnGetRuntimePermissionBackupCallback callback) {
+ @NonNull Consumer<byte[]> callback) {
checkNotNull(user);
checkNotNull(executor);
checkNotNull(callback);
+ // Check required permission to fail immediately instead of inside the oneway binder call
+ enforceSomePermissionsGrantedToSelf(Manifest.permission.GET_RUNTIME_PERMISSIONS);
+
mRemoteService.postAsync(service -> RemoteStream.receiveBytes(remotePipe -> {
service.getRuntimePermissionBackup(user, remotePipe);
})).whenCompleteAsync((bytes, err) -> {
if (err != null) {
Log.e(TAG, "Error getting permission backup", err);
- callback.onGetRuntimePermissionsBackup(EmptyArray.BYTE);
+ callback.accept(EmptyArray.BYTE);
} else {
- callback.onGetRuntimePermissionsBackup(bytes);
+ callback.accept(bytes);
}
}, executor);
}
/**
- * Restore a backup of the runtime permissions.
+ * Restore a {@link #getRuntimePermissionBackup backup-file} of the runtime permissions.
*
- * @param backup the backup to restore. The backup is sent asynchronously, hence it should not
- * be modified after calling this method.
+ * <p>This might leave some part of the backup-file unapplied if an package mentioned in the
+ * backup-file is not yet installed. It is required that
+ * {@link #applyStagedRuntimePermissionBackup} is called after any package is installed to
+ * apply the rest of the backup-file.
+ *
+ * @param backup the backup-file to restore. The backup is sent asynchronously, hence it should
+ * not be modified after calling this method.
* @param user The user to be restore
- *
- * @hide
*/
- @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
- public void restoreRuntimePermissionBackup(@NonNull byte[] backup, @NonNull UserHandle user) {
+ @RequiresPermission(anyOf = {
+ Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS
+ })
+ public void stageAndApplyRuntimePermissionsBackup(@NonNull byte[] backup,
+ @NonNull UserHandle user) {
checkNotNull(backup);
checkNotNull(user);
+ // Check required permission to fail immediately instead of inside the oneway binder call
+ enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
+
mRemoteService.postAsync(service -> RemoteStream.sendBytes(remotePipe -> {
- service.restoreRuntimePermissionBackup(user, remotePipe);
+ service.stageAndApplyRuntimePermissionsBackup(user, remotePipe);
}, backup))
.whenComplete((nullResult, err) -> {
if (err != null) {
@@ -407,17 +423,22 @@
}
/**
- * Restore a backup of the runtime permissions that has been delayed.
+ * Restore unapplied parts of a {@link #stageAndApplyRuntimePermissionsBackup previously staged}
+ * backup-file of the runtime permissions.
+ *
+ * <p>This should be called every time after a package is installed until the callback
+ * reports that there is no more unapplied backup left.
*
* @param packageName The package that is ready to have it's permissions restored.
- * @param user The user to restore
+ * @param user The user the package belongs to
* @param executor Executor to execute the callback on
- * @param callback Is called with {@code true} iff there is still more delayed backup left
- *
- * @hide
+ * @param callback Is called with {@code true} iff there is still more unapplied backup left
*/
- @RequiresPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
- public void restoreDelayedRuntimePermissionBackup(@NonNull String packageName,
+ @RequiresPermission(anyOf = {
+ Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS
+ })
+ public void applyStagedRuntimePermissionBackup(@NonNull String packageName,
@NonNull UserHandle user,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<Boolean> callback) {
@@ -426,13 +447,17 @@
checkNotNull(executor);
checkNotNull(callback);
+ // Check required permission to fail immediately instead of inside the oneway binder call
+ enforceSomePermissionsGrantedToSelf(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
+
mRemoteService.postAsync(service -> {
- AndroidFuture<Boolean> restoreDelayedRuntimePermissionBackupResult =
+ AndroidFuture<Boolean> applyStagedRuntimePermissionBackupResult =
new AndroidFuture<>();
- service.restoreDelayedRuntimePermissionBackup(packageName, user,
- restoreDelayedRuntimePermissionBackupResult);
- return restoreDelayedRuntimePermissionBackupResult;
- }).whenCompleteAsync((restoreDelayedRuntimePermissionBackupResult, err) -> {
+ service.applyStagedRuntimePermissionBackup(packageName, user,
+ applyStagedRuntimePermissionBackupResult);
+ return applyStagedRuntimePermissionBackupResult;
+ }).whenCompleteAsync((applyStagedRuntimePermissionBackupResult, err) -> {
long token = Binder.clearCallingIdentity();
try {
if (err != null) {
@@ -440,7 +465,7 @@
callback.accept(true);
} else {
callback.accept(
- Boolean.TRUE.equals(restoreDelayedRuntimePermissionBackupResult));
+ Boolean.TRUE.equals(applyStagedRuntimePermissionBackupResult));
}
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 7363d77..8f765fa 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -54,6 +54,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -105,31 +106,54 @@
public abstract void onGetRuntimePermissionsBackup(@NonNull UserHandle user,
@NonNull OutputStream backup, @NonNull Runnable callback);
+
+ /**
+ * @deprecated Implement {@link #onStageAndApplyRuntimePermissionsBackup} instead
+ */
+ @Deprecated
+ @BinderThread
+ public void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
+ @NonNull InputStream backup, @NonNull Runnable callback) {
+ }
+
/**
* Restore a backup of the runtime permissions.
*
* <p>If an app mentioned in the backup is not installed the state should be saved to later
- * be restored via {@link #onRestoreDelayedRuntimePermissionsBackup}.
+ * be restored via {@link #onApplyStagedRuntimePermissionBackup}.
*
* @param user The user to restore
* @param backup The stream to read the backup from
* @param callback Callback waiting for operation to be complete
*/
@BinderThread
- public abstract void onRestoreRuntimePermissionsBackup(@NonNull UserHandle user,
- @NonNull InputStream backup, @NonNull Runnable callback);
+ public void onStageAndApplyRuntimePermissionsBackup(@NonNull UserHandle user,
+ @NonNull InputStream backup, @NonNull Runnable callback) {
+ onRestoreRuntimePermissionsBackup(user, backup, callback);
+ }
+
+ /**
+ * @deprecated Implement {@link #onApplyStagedRuntimePermissionBackup} instead
+ */
+ @Deprecated
+ @BinderThread
+ public void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
+ }
/**
* Restore the permission state of an app that was provided in
- * {@link #onRestoreRuntimePermissionsBackup} but could not be restored back then.
+ * {@link #onStageAndApplyRuntimePermissionsBackup} but could not be restored back then.
*
* @param packageName The app to restore
* @param user The user to restore
* @param callback Callback waiting for whether there is still delayed backup left
*/
@BinderThread
- public abstract void onRestoreDelayedRuntimePermissionsBackup(@NonNull String packageName,
- @NonNull UserHandle user, @NonNull Consumer<Boolean> callback);
+ public void onApplyStagedRuntimePermissionBackup(@NonNull String packageName,
+ @NonNull UserHandle user, @NonNull Consumer<Boolean> callback) {
+ onRestoreDelayedRuntimePermissionsBackup(packageName, user, callback);
+ }
/**
* Gets the runtime permissions for an app.
@@ -238,7 +262,8 @@
request.put(packageName, permissions);
}
- enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
// Verify callerPackageName
try {
@@ -258,12 +283,33 @@
});
}
+ /**
+ * Throw a {@link SecurityException} if not at least one of the permissions is granted.
+ *
+ * @param requiredPermissions A list of permissions. Any of of them if sufficient to
+ * pass the check
+ */
+ private void enforceSomePermissionsGrantedToCaller(
+ @NonNull String... requiredPermissions) {
+ for (String requiredPermission : requiredPermissions) {
+ if (checkCallingPermission(requiredPermission)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ }
+
+ throw new SecurityException(
+ "At lest one of the following permissions is required: " + Arrays.toString(
+ requiredPermissions));
+ }
+
+
@Override
public void getRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
checkNotNull(user);
checkNotNull(pipe);
- enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
try (OutputStream backup = new ParcelFileDescriptor.AutoCloseOutputStream(pipe)) {
CountDownLatch latch = new CountDownLatch(1);
@@ -277,15 +323,17 @@
}
@Override
- public void restoreRuntimePermissionBackup(UserHandle user, ParcelFileDescriptor pipe) {
+ public void stageAndApplyRuntimePermissionsBackup(UserHandle user,
+ ParcelFileDescriptor pipe) {
checkNotNull(user);
checkNotNull(pipe);
- enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
try (InputStream backup = new ParcelFileDescriptor.AutoCloseInputStream(pipe)) {
CountDownLatch latch = new CountDownLatch(1);
- onRestoreRuntimePermissionsBackup(user, backup, latch::countDown);
+ onStageAndApplyRuntimePermissionsBackup(user, backup, latch::countDown);
latch.await();
} catch (IOException e) {
Log.e(LOG_TAG, "Could not open pipe to read backup from", e);
@@ -295,15 +343,16 @@
}
@Override
- public void restoreDelayedRuntimePermissionBackup(String packageName, UserHandle user,
+ public void applyStagedRuntimePermissionBackup(String packageName, UserHandle user,
AndroidFuture callback) {
checkNotNull(packageName);
checkNotNull(user);
checkNotNull(callback);
- enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+ Manifest.permission.RESTORE_RUNTIME_PERMISSIONS);
- onRestoreDelayedRuntimePermissionsBackup(packageName, user, callback::complete);
+ onApplyStagedRuntimePermissionBackup(packageName, user, callback::complete);
}
@Override
@@ -311,7 +360,7 @@
checkNotNull(packageName, "packageName");
checkNotNull(callback, "callback");
- enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
onGetAppPermissions(packageName, callback::complete);
}
@@ -321,7 +370,8 @@
checkNotNull(packageName, "packageName");
checkNotNull(permissionName, "permissionName");
- enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
CountDownLatch latch = new CountDownLatch(1);
PermissionControllerService.this.onRevokeRuntimePermission(packageName,
@@ -340,7 +390,7 @@
checkFlagsArgument(flags, COUNT_WHEN_SYSTEM | COUNT_ONLY_WHEN_GRANTED);
checkNotNull(callback, "callback");
- enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
onCountPermissionApps(permissionNames, flags, callback::complete);
}
@@ -351,7 +401,7 @@
checkArgumentNonnegative(numMillis);
checkNotNull(callback, "callback");
- enforceCallingPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(Manifest.permission.GET_RUNTIME_PERMISSIONS);
onGetPermissionUsages(countSystem, numMillis, callback::complete);
}
@@ -369,15 +419,17 @@
checkNotNull(callback);
if (grantState == PERMISSION_GRANT_STATE_DENIED) {
- enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.GRANT_RUNTIME_PERMISSIONS);
}
if (grantState == PERMISSION_GRANT_STATE_DENIED) {
- enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.REVOKE_RUNTIME_PERMISSIONS);
}
- enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
- null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
packageName, permission, grantState, callback::complete);
@@ -387,8 +439,8 @@
public void grantOrUpgradeDefaultRuntimePermissions(@NonNull AndroidFuture callback) {
checkNotNull(callback, "callback");
- enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
- null);
+ enforceSomePermissionsGrantedToCaller(
+ Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
onGrantOrUpgradeDefaultRuntimePermissions(() -> callback.complete(true));
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 457dcc0..065ee0b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8241,20 +8241,6 @@
public static final String AWARE_LOCK_ENABLED = "aware_lock_enabled";
/**
- * The settings values which should only be restored if the target device is the
- * same as the source device
- *
- * NOTE: Settings are backed up and restored in the order they appear
- * in this array. If you have one setting depending on another,
- * make sure that they are ordered appropriately.
- *
- * @hide
- */
- public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = {
- DISPLAY_DENSITY_FORCED,
- };
-
- /**
* Keys we no longer back up under the current schema, but want to continue to
* process when restoring historical backup datasets.
*
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5c1e13b..f98ea2c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3511,6 +3511,13 @@
<permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows the system to restore runtime permission state. This might grant
+ permissions, hence this is a more scoped, less powerful variant of GRANT_RUNTIME_PERMISSIONS.
+ Among other restrictions this cannot override user choices.
+ @hide -->
+ <permission android:name="android.permission.RESTORE_RUNTIME_PERMISSIONS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to change policy_fixed permissions.
@hide -->
<permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
diff --git a/data/etc/framework-sysconfig.xml b/data/etc/framework-sysconfig.xml
index 987c3b4..7296cfd 100644
--- a/data/etc/framework-sysconfig.xml
+++ b/data/etc/framework-sysconfig.xml
@@ -29,6 +29,8 @@
'service' attribute here is a flattened ComponentName string. -->
<backup-transport-whitelisted-service
service="com.android.localtransport/.LocalTransportService" />
+ <backup-transport-whitelisted-service
+ service="com.android.encryptedlocaltransport/.EncryptedLocalTransportService" />
<!-- Whitelist Shell to use the bugreport API -->
<bugreport-whitelisted package="com.android.shell" />
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index bf23634..254456c 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -350,7 +350,7 @@
* access manually.
*/
public static final String KEY_ALIAS_SELECTION_DENIED =
- "alias-selection-denied-ef829e15-210a-409d-96c9-ee684fc41972";
+ "android:alias-selection-denied";
/**
* Returns an {@code Intent} that can be used for credential
diff --git a/packages/BackupEncryption/Android.bp b/packages/BackupEncryption/Android.bp
index 342d796..68e937c 100644
--- a/packages/BackupEncryption/Android.bp
+++ b/packages/BackupEncryption/Android.bp
@@ -17,8 +17,7 @@
android_app {
name: "BackupEncryption",
srcs: ["src/**/*.java"],
- libs: ["backup-encryption-protos"],
- static_libs: ["backuplib"],
+ static_libs: ["backup-encryption-protos", "backuplib"],
optimize: { enabled: false },
platform_apis: true,
certificate: "platform",
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java
new file mode 100644
index 0000000..2035b66
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/EncryptionKeyHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+class EncryptionKeyHelper {
+ private static SecureRandom sSecureRandom = new SecureRandom();
+
+ private final Context mContext;
+ private final RecoverableKeyStoreSecondaryKeyManager
+ .RecoverableKeyStoreSecondaryKeyManagerProvider
+ mSecondaryKeyManagerProvider;
+
+ EncryptionKeyHelper(Context context) {
+ mContext = context;
+ mSecondaryKeyManagerProvider =
+ () ->
+ new RecoverableKeyStoreSecondaryKeyManager(
+ RecoveryController.getInstance(mContext), sSecureRandom);
+ }
+
+ RecoverableKeyStoreSecondaryKeyManager
+ .RecoverableKeyStoreSecondaryKeyManagerProvider getKeyManagerProvider() {
+ return mSecondaryKeyManagerProvider;
+ }
+
+ RecoverableKeyStoreSecondaryKey getActiveSecondaryKey()
+ throws UnrecoverableKeyException, InternalRecoveryServiceException {
+ String keyAlias = CryptoSettings.getInstance(mContext).getActiveSecondaryKeyAlias().get();
+ return mSecondaryKeyManagerProvider.get().get(keyAlias).get();
+ }
+
+ SecretKey getTertiaryKey(
+ String packageName,
+ RecoverableKeyStoreSecondaryKey secondaryKey)
+ throws IllegalBlockSizeException, InvalidAlgorithmParameterException,
+ NoSuchAlgorithmException, IOException, NoSuchPaddingException,
+ InvalidKeyException {
+ TertiaryKeyManager tertiaryKeyManager =
+ new TertiaryKeyManager(
+ mContext,
+ sSecureRandom,
+ TertiaryKeyRotationScheduler.getInstance(mContext),
+ secondaryKey,
+ packageName);
+ return tertiaryKeyManager.getKey();
+ }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java
new file mode 100644
index 0000000..1d841b4
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/KeyValueEncrypter.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import static com.android.server.backup.encryption.BackupEncryptionService.TAG;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.KeyWrapUtils;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+import com.android.server.backup.encryption.tasks.EncryptedKvBackupTask;
+import com.android.server.backup.encryption.tasks.EncryptedKvRestoreTask;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Map;
+
+public class KeyValueEncrypter {
+ private final Context mContext;
+ private final EncryptionKeyHelper mKeyHelper;
+
+ public KeyValueEncrypter(Context context) {
+ mContext = context;
+ mKeyHelper = new EncryptionKeyHelper(mContext);
+ }
+
+ public void encryptKeyValueData(
+ String packageName, ParcelFileDescriptor inputFd, OutputStream outputStream)
+ throws Exception {
+ EncryptedKvBackupTask.EncryptedKvBackupTaskFactory backupTaskFactory =
+ new EncryptedKvBackupTask.EncryptedKvBackupTaskFactory();
+ EncryptedKvBackupTask backupTask =
+ backupTaskFactory.newInstance(
+ mContext,
+ new SecureRandom(),
+ new FileBackupServer(outputStream),
+ CryptoSettings.getInstance(mContext),
+ mKeyHelper.getKeyManagerProvider(),
+ inputFd,
+ packageName);
+ backupTask.performBackup(/* incremental */ false);
+ }
+
+ public void decryptKeyValueData(String packageName,
+ InputStream encryptedInputStream, ParcelFileDescriptor outputFd) throws Exception {
+ RecoverableKeyStoreSecondaryKey secondaryKey = mKeyHelper.getActiveSecondaryKey();
+
+ EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory restoreTaskFactory =
+ new EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory();
+ EncryptedKvRestoreTask restoreTask =
+ restoreTaskFactory.newInstance(
+ mContext,
+ mKeyHelper.getKeyManagerProvider(),
+ new InputStreamFullRestoreDownloader(encryptedInputStream),
+ secondaryKey.getAlias(),
+ KeyWrapUtils.wrap(
+ secondaryKey.getSecretKey(),
+ mKeyHelper.getTertiaryKey(packageName, secondaryKey)));
+
+ restoreTask.getRestoreData(outputFd);
+ }
+
+ // TODO(b/142455725): Extract into a commong class.
+ private static class FileBackupServer implements CryptoBackupServer {
+ private static final String EMPTY_DOC_ID = "";
+
+ private final OutputStream mOutputStream;
+
+ FileBackupServer(OutputStream outputStream) {
+ mOutputStream = outputStream;
+ }
+
+ @Override
+ public String uploadIncrementalBackup(
+ String packageName,
+ String oldDocId,
+ byte[] diffScript,
+ WrappedKeyProto.WrappedKey tertiaryKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String uploadNonIncrementalBackup(
+ String packageName, byte[] data, WrappedKeyProto.WrappedKey tertiaryKey) {
+ try {
+ mOutputStream.write(data);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write encrypted data to file: ", e);
+ }
+
+ return EMPTY_DOC_ID;
+ }
+
+ @Override
+ public void setActiveSecondaryKeyAlias(
+ String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) {
+ // Do nothing.
+ }
+ }
+
+ // TODO(b/142455725): Extract into a commong class.
+ private static class InputStreamFullRestoreDownloader extends FullRestoreDownloader {
+ private final InputStream mInputStream;
+
+ InputStreamFullRestoreDownloader(InputStream inputStream) {
+ mInputStream = inputStream;
+ }
+
+ @Override
+ public int readNextChunk(byte[] buffer) throws IOException {
+ return mInputStream.read(buffer);
+ }
+
+ @Override
+ public void finish(FinishType finishType) {
+ try {
+ mInputStream.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Error while reading restore data");
+ }
+ }
+ }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
index 1d0224d..c3cb335 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransport.java
@@ -18,27 +18,58 @@
import static com.android.server.backup.encryption.BackupEncryptionService.TAG;
+import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.encryption.KeyValueEncrypter;
import com.android.server.backup.transport.DelegatingTransport;
import com.android.server.backup.transport.TransportClient;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.atomic.AtomicReference;
+
/**
* This is an implementation of {@link IBackupTransport} that encrypts (or decrypts) the data when
* sending it (or receiving it) from the {@link IBackupTransport} returned by {@link
* TransportClient.connect(String)}.
*/
public class IntermediateEncryptingTransport extends DelegatingTransport {
+ private static final String BACKUP_TEMP_DIR = "backup";
+ private static final String RESTORE_TEMP_DIR = "restore";
+
private final TransportClient mTransportClient;
private final Object mConnectLock = new Object();
+ private final Context mContext;
private volatile IBackupTransport mRealTransport;
+ private AtomicReference<String> mNextRestorePackage = new AtomicReference<>();
+ private final KeyValueEncrypter mKeyValueEncrypter;
+ private final boolean mShouldEncrypt;
+
+ IntermediateEncryptingTransport(
+ TransportClient transportClient, Context context, boolean shouldEncrypt) {
+ this(transportClient, context, new KeyValueEncrypter(context), shouldEncrypt);
+ }
@VisibleForTesting
- IntermediateEncryptingTransport(TransportClient transportClient) {
+ IntermediateEncryptingTransport(
+ TransportClient transportClient, Context context, KeyValueEncrypter keyValueEncrypter,
+ boolean shouldEncrypt) {
mTransportClient = transportClient;
+ mContext = context;
+ mKeyValueEncrypter = keyValueEncrypter;
+ mShouldEncrypt = shouldEncrypt;
}
@Override
@@ -46,9 +77,116 @@
if (mRealTransport == null) {
connect();
}
+ Log.d(TAG, "real transport = " + mRealTransport.name());
return mRealTransport;
}
+ @Override
+ public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
+ throws RemoteException {
+ if (!mShouldEncrypt) {
+ return super.performBackup(packageInfo, inFd, flags);
+ }
+
+ File encryptedStorageFile = getBackupTempStorage(packageInfo.packageName);
+ if (encryptedStorageFile == null) {
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ // Encrypt the backup data and write it into a temp file.
+ try (OutputStream encryptedOutput = new FileOutputStream(encryptedStorageFile)) {
+ mKeyValueEncrypter.encryptKeyValueData(packageInfo.packageName, inFd,
+ encryptedOutput);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failed to encrypt backup data: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ // Pass the temp file to the real transport for backup.
+ try (FileInputStream encryptedInput = new FileInputStream(encryptedStorageFile)) {
+ return super.performBackup(
+ packageInfo, ParcelFileDescriptor.dup(encryptedInput.getFD()), flags);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to read encrypted data from temp storage: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+ }
+
+ @Override
+ public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
+ if (!mShouldEncrypt) {
+ return super.getRestoreData(outFd);
+ }
+
+ String nextRestorePackage = mNextRestorePackage.get();
+ if (nextRestorePackage == null) {
+ Log.e(TAG, "No next restore package set");
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ File encryptedStorageFile = getRestoreTempStorage(nextRestorePackage);
+ if (encryptedStorageFile == null) {
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ // Get encrypted restore data from the real transport and write it into a temp file.
+ try (FileOutputStream outputStream = new FileOutputStream(encryptedStorageFile)) {
+ int status = super.getRestoreData(ParcelFileDescriptor.dup(outputStream.getFD()));
+ if (status != BackupTransport.TRANSPORT_OK) {
+ Log.e(TAG, "Failed to read restore data from transport, status = " + status);
+ return status;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write encrypted data to temp storage: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ // Decrypt the data and write it into the fd given by the real transport.
+ try (InputStream inputStream = new FileInputStream(encryptedStorageFile)) {
+ mKeyValueEncrypter.decryptKeyValueData(nextRestorePackage, inputStream, outFd);
+ encryptedStorageFile.delete();
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to decrypt restored data: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ @Override
+ public RestoreDescription nextRestorePackage() throws RemoteException {
+ if (!mShouldEncrypt) {
+ return super.nextRestorePackage();
+ }
+
+ RestoreDescription restoreDescription = super.nextRestorePackage();
+ mNextRestorePackage.set(restoreDescription.getPackageName());
+
+ return restoreDescription;
+ }
+
+ @VisibleForTesting
+ protected File getBackupTempStorage(String packageName) {
+ return getTempStorage(packageName, BACKUP_TEMP_DIR);
+ }
+
+ @VisibleForTesting
+ protected File getRestoreTempStorage(String packageName) {
+ return getTempStorage(packageName, RESTORE_TEMP_DIR);
+ }
+
+ private File getTempStorage(String packageName, String operationType) {
+ File encryptedDir = new File(mContext.getFilesDir(), operationType);
+ encryptedDir.mkdir();
+ File encryptedFile = new File(encryptedDir, packageName);
+ try {
+ encryptedFile.createNewFile();
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to create temp file for encrypted data: ", e);
+ }
+ return encryptedFile;
+ }
+
private void connect() throws RemoteException {
Log.i(TAG, "connecting " + mTransportClient);
synchronized (mConnectLock) {
@@ -65,4 +203,9 @@
TransportClient getClient() {
return mTransportClient;
}
+
+ @VisibleForTesting
+ void setNextRestorePackage(String nextRestorePackage) {
+ mNextRestorePackage.set(nextRestorePackage);
+ }
}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
index 6e6d571..7c4082c 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportManager.java
@@ -26,20 +26,20 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.backup.transport.TransportClientManager;
import com.android.server.backup.transport.TransportStats;
import java.util.HashMap;
import java.util.Map;
-/**
- * Handles creation and cleanup of {@link IntermediateEncryptingTransport} instances.
- */
+/** Handles creation and cleanup of {@link IntermediateEncryptingTransport} instances. */
public class IntermediateEncryptingTransportManager {
private static final String CALLER = "IntermediateEncryptingTransportManager";
private final TransportClientManager mTransportClientManager;
private final Object mTransportsLock = new Object();
private final Map<ComponentName, IntermediateEncryptingTransport> mTransports = new HashMap<>();
+ private Context mContext;
@VisibleForTesting
IntermediateEncryptingTransportManager(TransportClientManager transportClientManager) {
@@ -48,6 +48,7 @@
public IntermediateEncryptingTransportManager(Context context) {
this(new TransportClientManager(UserHandle.myUserId(), context, new TransportStats()));
+ mContext = context;
}
/**
@@ -55,31 +56,42 @@
* provide a {@link IntermediateEncryptingTransport} which is an implementation of {@link
* IBackupTransport} that encrypts (or decrypts) the data when sending it (or receiving it) from
* the real {@link IBackupTransport}.
+ *
* @param intent {@link Intent} created with a call to {@link
- * TransportClientManager.getEncryptingTransportIntent(ComponentName)}.
+ * TransportClientManager.getEncryptingTransportIntent(ComponentName)}.
* @return
*/
public IntermediateEncryptingTransport get(Intent intent) {
Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
Log.i(TAG, "get: intent:" + intent + " transportIntent:" + transportIntent);
synchronized (mTransportsLock) {
- return mTransports.computeIfAbsent(transportIntent.getComponent(),
- c -> create(transportIntent));
+ return mTransports.computeIfAbsent(
+ transportIntent.getComponent(), c -> create(transportIntent));
}
}
- /**
- * Create an instance of {@link IntermediateEncryptingTransport}.
- */
+ /** Create an instance of {@link IntermediateEncryptingTransport}. */
private IntermediateEncryptingTransport create(Intent realTransportIntent) {
Log.d(TAG, "create: intent:" + realTransportIntent);
- return new IntermediateEncryptingTransport(mTransportClientManager.getTransportClient(
- realTransportIntent.getComponent(), realTransportIntent.getExtras(), CALLER));
+
+ LockPatternUtils patternUtils = new LockPatternUtils(mContext);
+ boolean shouldEncrypt =
+ realTransportIntent.getComponent().getClassName().contains("EncryptedLocalTransport")
+ && (patternUtils.isLockPatternEnabled(UserHandle.myUserId())
+ || patternUtils.isLockPasswordEnabled(UserHandle.myUserId()));
+
+ return new IntermediateEncryptingTransport(
+ mTransportClientManager.getTransportClient(
+ realTransportIntent.getComponent(),
+ realTransportIntent.getExtras(),
+ CALLER),
+ mContext,
+ shouldEncrypt);
}
/**
- * Cleanup the {@link IntermediateEncryptingTransport} which was created by a call to
- * {@link #get(Intent)} with this {@link Intent}.
+ * Cleanup the {@link IntermediateEncryptingTransport} which was created by a call to {@link
+ * #get(Intent)} with this {@link Intent}.
*/
public void cleanup(Intent intent) {
Intent transportIntent = TransportClientManager.getRealTransportIntent(intent);
diff --git a/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java b/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
index cc4b0ab..a85b2e4 100644
--- a/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
+++ b/packages/BackupEncryption/test/unittest/src/com/android/server/backup/encryption/transport/IntermediateEncryptingTransportTest.java
@@ -18,43 +18,71 @@
import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.backup.BackupTransport;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.encryption.KeyValueEncrypter;
import com.android.server.backup.transport.TransportClient;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.File;
+
@Presubmit
@RunWith(AndroidJUnit4.class)
public class IntermediateEncryptingTransportTest {
- @Mock private IBackupTransport mRealTransport;
- @Mock private TransportClient mTransportClient;
+ private static final String TEST_PACKAGE_NAME = "test_package";
private IntermediateEncryptingTransport mIntermediateEncryptingTransport;
+ private final PackageInfo mTestPackage = new PackageInfo();
+
+ @Mock private IBackupTransport mRealTransport;
+ @Mock private TransportClient mTransportClient;
+ @Mock private ParcelFileDescriptor mParcelFileDescriptor;
+ @Mock private KeyValueEncrypter mKeyValueEncrypter;
+ @Mock private Context mContext;
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ private File mTempFile;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mIntermediateEncryptingTransport = new IntermediateEncryptingTransport(mTransportClient);
+
+ mIntermediateEncryptingTransport =
+ new IntermediateEncryptingTransport(
+ mTransportClient, mContext, mKeyValueEncrypter, true);
+ mTestPackage.packageName = TEST_PACKAGE_NAME;
+ mTempFile = mTemporaryFolder.newFile();
+
+ when(mTransportClient.connect(anyString())).thenReturn(mRealTransport);
+ when(mRealTransport.getRestoreData(any())).thenReturn(BackupTransport.TRANSPORT_OK);
}
@Test
public void testGetDelegate_callsConnect() throws Exception {
- when(mTransportClient.connect(anyString())).thenReturn(mRealTransport);
-
IBackupTransport ret = mIntermediateEncryptingTransport.getDelegate();
assertEquals(mRealTransport, ret);
@@ -74,4 +102,79 @@
verify(mTransportClient, times(1)).connect(anyString());
verifyNoMoreInteractions(mTransportClient);
}
+
+ @Test
+ public void testPerformBackup_shouldEncryptTrue_encryptsDataAndPassesToDelegate()
+ throws Exception {
+ mIntermediateEncryptingTransport =
+ new TestIntermediateTransport(mTransportClient, mContext, mKeyValueEncrypter, true);
+
+ mIntermediateEncryptingTransport.performBackup(mTestPackage, mParcelFileDescriptor, 0);
+
+ verify(mKeyValueEncrypter, times(1))
+ .encryptKeyValueData(eq(TEST_PACKAGE_NAME), eq(mParcelFileDescriptor), any());
+ verify(mRealTransport, times(1)).performBackup(eq(mTestPackage), any(), eq(0));
+ }
+
+ @Test
+ public void testPerformBackup_shouldEncryptFalse_doesntEncryptDataAndPassedToDelegate()
+ throws Exception {
+ mIntermediateEncryptingTransport =
+ new TestIntermediateTransport(
+ mTransportClient, mContext, mKeyValueEncrypter, false);
+
+ mIntermediateEncryptingTransport.performBackup(mTestPackage, mParcelFileDescriptor, 0);
+
+ verifyZeroInteractions(mKeyValueEncrypter);
+ verify(mRealTransport, times(1))
+ .performBackup(eq(mTestPackage), eq(mParcelFileDescriptor), eq(0));
+ }
+
+ @Test
+ public void testGetRestoreData_shouldEncryptTrue_decryptsDataAndPassesToDelegate()
+ throws Exception {
+ mIntermediateEncryptingTransport =
+ new TestIntermediateTransport(mTransportClient, mContext, mKeyValueEncrypter, true);
+ mIntermediateEncryptingTransport.setNextRestorePackage(TEST_PACKAGE_NAME);
+
+ mIntermediateEncryptingTransport.getRestoreData(mParcelFileDescriptor);
+
+ verify(mKeyValueEncrypter, times(1))
+ .decryptKeyValueData(eq(TEST_PACKAGE_NAME), any(), eq(mParcelFileDescriptor));
+ verify(mRealTransport, times(1)).getRestoreData(any());
+ }
+
+ @Test
+ public void testGetRestoreData_shouldEncryptFalse_doesntDecryptDataAndPassesToDelegate()
+ throws Exception {
+ mIntermediateEncryptingTransport =
+ new TestIntermediateTransport(
+ mTransportClient, mContext, mKeyValueEncrypter, false);
+ mIntermediateEncryptingTransport.setNextRestorePackage(TEST_PACKAGE_NAME);
+
+ mIntermediateEncryptingTransport.getRestoreData(mParcelFileDescriptor);
+
+ verifyZeroInteractions(mKeyValueEncrypter);
+ verify(mRealTransport, times(1)).getRestoreData(eq(mParcelFileDescriptor));
+ }
+
+ private final class TestIntermediateTransport extends IntermediateEncryptingTransport {
+ TestIntermediateTransport(
+ TransportClient transportClient,
+ Context context,
+ KeyValueEncrypter keyValueEncrypter,
+ boolean shouldEncrypt) {
+ super(transportClient, context, keyValueEncrypter, shouldEncrypt);
+ }
+
+ @Override
+ protected File getBackupTempStorage(String packageName) {
+ return mTempFile;
+ }
+
+ @Override
+ protected File getRestoreTempStorage(String packageName) {
+ return mTempFile;
+ }
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 9d47cdc..90aba2f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -113,6 +113,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -304,7 +305,8 @@
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
StatusBarWindowViewController.Builder statusBarWindowViewControllerBuild,
- NotifLog notifLog) {
+ NotifLog notifLog,
+ DozeParameters dozeParameters) {
super(
context,
lightBarController,
@@ -360,7 +362,8 @@
configurationController,
statusBarWindowController,
statusBarWindowViewControllerBuild,
- notifLog);
+ notifLog,
+ dozeParameters);
mNavigationBarController = navigationBarController;
}
diff --git a/packages/EncryptedLocalTransport/Android.bp b/packages/EncryptedLocalTransport/Android.bp
new file mode 100644
index 0000000..dd30ad1
--- /dev/null
+++ b/packages/EncryptedLocalTransport/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+ name: "EncryptedLocalTransport",
+ srcs: ["src/**/*.java"],
+ optimize: {
+ proguard_flags_files: ["proguard.flags"],
+ },
+ static_libs: ["LocalTransport"],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+}
diff --git a/packages/EncryptedLocalTransport/AndroidManifest.xml b/packages/EncryptedLocalTransport/AndroidManifest.xml
new file mode 100644
index 0000000..dc3617f
--- /dev/null
+++ b/packages/EncryptedLocalTransport/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2019 Google Inc.
+ *
+ * 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.encryptedlocaltransport"
+ android:sharedUserId="android.uid.system" >
+
+
+ <application android:allowBackup="false" >
+ <!-- This service does not need to be exported because it shares uid with the system server
+ which is the only client. -->
+ <service android:name=".EncryptedLocalTransportService"
+ android:permission="android.permission.CONFIRM_FULL_BACKUP"
+ android:exported="false">
+ <intent-filter>
+ <action android:name="android.backup.TRANSPORT_HOST" />
+ </intent-filter>
+ </service>
+
+ </application>
+</manifest>
diff --git a/packages/EncryptedLocalTransport/proguard.flags b/packages/EncryptedLocalTransport/proguard.flags
new file mode 100644
index 0000000..e4ce3c5
--- /dev/null
+++ b/packages/EncryptedLocalTransport/proguard.flags
@@ -0,0 +1,2 @@
+-keep class com.android.localTransport.EncryptedLocalTransport
+-keep class com.android.localTransport.EncryptedLocalTransportService
diff --git a/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java
new file mode 100644
index 0000000..3dd453e
--- /dev/null
+++ b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransport.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.encryptedlocaltransport;
+
+import android.app.backup.BackupTransport;
+import android.app.backup.RestoreDescription;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
+import android.util.Log;
+
+import com.android.localtransport.LocalTransport;
+import com.android.localtransport.LocalTransportParameters;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+
+public class EncryptedLocalTransport extends LocalTransport {
+ private static final String TAG = "EncryptedLocalTransport";
+ private static final int BACKUP_BUFFER_SIZE = 32 * 1024; // 32 KB.
+
+ public EncryptedLocalTransport(Context context,
+ LocalTransportParameters parameters) {
+ super(context, parameters);
+ }
+
+ @Override
+ public int performBackup(
+ PackageInfo packageInfo, ParcelFileDescriptor data, int flags) {
+ File packageFile;
+ try {
+ StructStat stat = Os.fstat(data.getFileDescriptor());
+ if (stat.st_size > KEY_VALUE_BACKUP_SIZE_QUOTA) {
+ Log.w(TAG, "New datastore size " + stat.st_size
+ + " exceeds quota " + KEY_VALUE_BACKUP_SIZE_QUOTA);
+ return TRANSPORT_QUOTA_EXCEEDED;
+ }
+ } catch (ErrnoException e) {
+ Log.w(TAG, "Failed to stat the backup input file: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ clearBackupData(packageInfo);
+
+ try (InputStream in = new FileInputStream(data.getFileDescriptor())) {
+ packageFile = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
+ Files.copy(in, packageFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to save backup data to file: ", e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ return TRANSPORT_OK;
+ }
+
+ @Override
+ public int getRestoreData(ParcelFileDescriptor outFd) {
+ if (mRestorePackages == null) {
+ throw new IllegalStateException("startRestore not called");
+ }
+ if (mRestorePackage < 0) {
+ throw new IllegalStateException("nextRestorePackage not called");
+ }
+ if (mRestoreType != RestoreDescription.TYPE_KEY_VALUE) {
+ throw new IllegalStateException("getRestoreData(fd) for non-key/value dataset");
+ }
+
+ try(OutputStream out = new FileOutputStream(outFd.getFileDescriptor())) {
+ File packageFile = new File(mRestoreSetIncrementalDir,
+ mRestorePackages[mRestorePackage].packageName);
+ Files.copy(packageFile.toPath(), out);
+ } catch (IOException e) {
+ Log.d(TAG, "Failed to transfer restore data: " + e);
+ return BackupTransport.TRANSPORT_ERROR;
+ }
+
+ return BackupTransport.TRANSPORT_OK;
+ }
+
+ @Override
+ protected boolean hasRestoreDataForPackage(String packageName) {
+ File contents = (new File(mRestoreSetIncrementalDir, packageName));
+ return contents.exists() && contents.length() != 0;
+
+ }
+}
diff --git a/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java
new file mode 100644
index 0000000..952f90d
--- /dev/null
+++ b/packages/EncryptedLocalTransport/src/com/android/encryptedlocaltransport/EncryptedLocalTransportService.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.encryptedlocaltransport;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.localtransport.LocalTransportParameters;
+
+public class EncryptedLocalTransportService extends Service {
+ private static EncryptedLocalTransport sTransport = null;
+
+ @Override
+ public void onCreate() {
+ if (sTransport == null) {
+ LocalTransportParameters parameters =
+ new LocalTransportParameters(getMainThreadHandler(), getContentResolver());
+ sTransport = new EncryptedLocalTransport(this, parameters);
+ }
+ sTransport.getParameters().start();
+ }
+
+ @Override
+ public void onDestroy() {
+ sTransport.getParameters().stop();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sTransport.getBinder();
+ }
+}
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index be3bcc7..50f858e 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -72,19 +72,19 @@
// Size quotas at reasonable values, similar to the current cloud-storage limits
private static final long FULL_BACKUP_SIZE_QUOTA = 25 * 1024 * 1024;
- private static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
+ protected static final long KEY_VALUE_BACKUP_SIZE_QUOTA = 5 * 1024 * 1024;
private Context mContext;
private File mDataDir;
private File mCurrentSetDir;
- private File mCurrentSetIncrementalDir;
+ protected File mCurrentSetIncrementalDir;
private File mCurrentSetFullDir;
- private PackageInfo[] mRestorePackages = null;
- private int mRestorePackage = -1; // Index into mRestorePackages
- private int mRestoreType;
+ protected PackageInfo[] mRestorePackages = null;
+ protected int mRestorePackage = -1; // Index into mRestorePackages
+ protected int mRestoreType;
private File mRestoreSetDir;
- private File mRestoreSetIncrementalDir;
+ protected File mRestoreSetIncrementalDir;
private File mRestoreSetFullDir;
// Additional bookkeeping for full backup
@@ -116,7 +116,7 @@
makeDataDirs();
}
- LocalTransportParameters getParameters() {
+ public LocalTransportParameters getParameters() {
return mParameters;
}
@@ -545,14 +545,14 @@
int bytesLeft = numBytes;
while (bytesLeft > 0) {
try {
- int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
- if (nRead < 0) {
- // Something went wrong if we expect data but saw EOD
- Log.w(TAG, "Unexpected EOD; failing backup");
- return TRANSPORT_ERROR;
- }
- mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
- bytesLeft -= nRead;
+ int nRead = mSocketInputStream.read(mFullBackupBuffer, 0, bytesLeft);
+ if (nRead < 0) {
+ // Something went wrong if we expect data but saw EOD
+ Log.w(TAG, "Unexpected EOD; failing backup");
+ return TRANSPORT_ERROR;
+ }
+ mFullBackupOutputStream.write(mFullBackupBuffer, 0, nRead);
+ bytesLeft -= nRead;
} catch (IOException e) {
Log.e(TAG, "Error handling backup data for " + mFullTargetPackage);
return TRANSPORT_ERROR;
@@ -628,20 +628,15 @@
}
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
- boolean found = false;
+ boolean found;
while (++mRestorePackage < mRestorePackages.length) {
String name = mRestorePackages[mRestorePackage].packageName;
// If we have key/value data for this package, deliver that
// skip packages where we have a data dir but no actual contents
- String[] contents = (new File(mRestoreSetIncrementalDir, name)).list();
- if (contents != null && contents.length > 0) {
- if (DEBUG) {
- Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) @ "
- + mRestorePackage + " = " + name);
- }
+ found = hasRestoreDataForPackage(name);
+ if (found) {
mRestoreType = RestoreDescription.TYPE_KEY_VALUE;
- found = true;
}
if (!found) {
@@ -672,6 +667,18 @@
return RestoreDescription.NO_MORE_PACKAGES;
}
+ protected boolean hasRestoreDataForPackage(String packageName) {
+ String[] contents = (new File(mRestoreSetIncrementalDir, packageName)).list();
+ if (contents != null && contents.length > 0) {
+ if (DEBUG) {
+ Log.v(TAG, " nextRestorePackage(TYPE_KEY_VALUE) @ "
+ + mRestorePackage + " = " + packageName);
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
public int getRestoreData(ParcelFileDescriptor outFd) {
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
index 784be22..8b4db92 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransportParameters.java
@@ -22,7 +22,7 @@
import android.provider.Settings;
import android.util.KeyValueListParser;
-class LocalTransportParameters extends KeyValueSettingObserver {
+public class LocalTransportParameters extends KeyValueSettingObserver {
private static final String TAG = "LocalTransportParams";
private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
@@ -31,7 +31,7 @@
private boolean mFakeEncryptionFlag;
private boolean mIsNonIncrementalOnly;
- LocalTransportParameters(Handler handler, ContentResolver resolver) {
+ public LocalTransportParameters(Handler handler, ContentResolver resolver) {
super(handler, resolver, Settings.Secure.getUriFor(SETTING));
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS
index fad9ffc..541dd878 100644
--- a/packages/SettingsProvider/src/android/provider/settings/OWNERS
+++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS
@@ -1,2 +1,5 @@
# Please reach out to Android B&R when making Settings backup changes
-br-framework-team+reviews@google.com
+alsutton@google.com
+nathch@google.com
+rthakohov@google.com
+
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
new file mode 100644
index 0000000..e425790
--- /dev/null
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/DeviceSpecificSettings.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider.settings.backup;
+
+import android.provider.Settings;
+
+/** Device specific settings list */
+public class DeviceSpecificSettings {
+ /**
+ * The settings values which should only be restored if the target device is the
+ * same as the source device
+ *
+ * NOTE: Settings are backed up and restored in the order they appear
+ * in this array. If you have one setting depending on another,
+ * make sure that they are ordered appropriately.
+ *
+ * @hide
+ */
+ public static final String[] DEVICE_SPECIFIC_SETTINGS_TO_BACKUP = {
+ Settings.Secure.DISPLAY_DENSITY_FORCED,
+ };
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 976f336..ef67bbd 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -41,8 +41,8 @@
public class SecureSettingsValidators {
/**
* All settings in {@link Secure.SETTINGS_TO_BACKUP} and {@link
- * Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null validator, otherwise
- * they won't be restored.
+ * DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP} array *must* have a non-null
+ * validator, otherwise they won't be restored.
*/
public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index f545fa6..7e60452 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -34,6 +34,7 @@
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.settings.backup.DeviceSpecificSettings;
import android.provider.settings.backup.GlobalSettings;
import android.provider.settings.backup.SecureSettings;
import android.provider.settings.backup.SystemSettings;
@@ -641,7 +642,7 @@
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
Settings.Secure.LEGACY_RESTORE_SETTINGS,
- Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+ DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
validators = SecureSettingsValidators.VALIDATORS;
} else if (contentUri.equals(Settings.System.CONTENT_URI)) {
whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
@@ -1000,7 +1001,7 @@
getContentResolver()
.query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) {
return extractRelevantValues(
- cursor, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+ cursor, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
}
}
diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS
index a3b4e40..f3241ea 100644
--- a/packages/SettingsProvider/test/src/android/provider/OWNERS
+++ b/packages/SettingsProvider/test/src/android/provider/OWNERS
@@ -1,4 +1,4 @@
per-file * = *
# Please reach out to the Android B&R team for settings backup changes
-per-file SettingsBackupTest.java = br-framework-team+reviews@google.com
+per-file SettingsBackupTest.java = alsutton@google.com, nathch@google.com, rthakohov@google.com
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 8437eae..62827bc 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -16,6 +16,8 @@
package android.provider;
+import static android.provider.settings.backup.DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP;
+
import static com.google.android.collect.Sets.newHashSet;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -750,7 +752,7 @@
public void secureSettingsBackedUpOrBlacklisted() {
HashSet<String> keys = new HashSet<String>();
Collections.addAll(keys, SecureSettings.SETTINGS_TO_BACKUP);
- Collections.addAll(keys, Settings.Secure.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+ Collections.addAll(keys, DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
checkSettingsBackedUpOrBlacklisted(
getCandidateSettings(Settings.Secure.class),
keys,
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 83acfa0..656827a 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -46,3 +46,6 @@
#Android Auto
stenning@google.com
+#Android TV
+rgl@google.com
+
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
index cac673f..c1d4b03 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/HomeControlsPlugin.java
@@ -33,4 +33,9 @@
* will add home controls to this space.
*/
void sendParentGroup(ViewGroup group);
+
+ /**
+ * When visible, will poll for updates.
+ */
+ void setVisible(boolean visible);
}
diff --git a/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml
new file mode 100644
index 0000000..87684a3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_lightbulb_outline_gm2_24px.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M9,21c0,0.55 0.45,1 1,1h4c0.55,0 1,-0.45 1,-1v-1L9,20v1zM12,2C8.14,2 5,5.14 5,9c0,2.38 1.19,4.47 3,5.74L8,17c0,0.55 0.45,1 1,1h6c0.55,0 1,-0.45 1,-1v-2.26c1.81,-1.27 3,-3.36 3,-5.74 0,-3.86 -3.14,-7 -7,-7zM14.85,13.1l-0.85,0.6L14,16h-4v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,1.63 -0.8,3.16 -2.15,4.1z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/home_controls.xml b/packages/SystemUI/res/layout/home_controls.xml
new file mode 100644
index 0000000..bb971c2
--- /dev/null
+++ b/packages/SystemUI/res/layout/home_controls.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/home_controls_layout"
+ android:layout_width="match_parent"
+ android:layout_height="125dp"
+ android:layout_gravity="@integer/notification_panel_layout_gravity"
+ android:visibility="gone"
+ android:padding="8dp"
+ android:layout_margin="5dp"
+ android:background="?android:attr/colorBackgroundFloating"
+ android:orientation="vertical">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 0e59a41..4869be1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -51,17 +51,7 @@
systemui:viewType="com.android.systemui.plugins.qs.QS" />
<!-- Temporary area to test out home controls -->
- <LinearLayout
- android:id="@+id/home_controls_layout"
- android:layout_width="match_parent"
- android:layout_height="125dp"
- android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:visibility="gone"
- android:padding="8dp"
- android:layout_margin="5dp"
- android:background="?android:attr/colorBackgroundFloating"
- android:orientation="vertical">
- </LinearLayout>
+ <include layout="@layout/home_controls" />
<com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
android:id="@+id/notification_stack_scroller"
@@ -107,4 +97,4 @@
android:background="@drawable/qs_navbar_scrim" />
<include layout="@layout/status_bar_expanded_plugin_frame"/>
-</merge>
\ No newline at end of file
+</merge>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 105b27e..efcc2c4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -117,7 +117,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,controls
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8335c11..3cc683a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -129,6 +129,9 @@
<!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
<string name="usb_device_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_device">%2$s</xliff:g>?</string>
+ <!-- Prompt for the USB device confirm dialog with warning text for USB device dialogs. [CHAR LIMIT=200] -->
+ <string name="usb_device_confirm_prompt_warn">Open <xliff:g id="application" example= "Usb Mega Player">%1$s</xliff:g> to handle <xliff:g id="usb_device" example="USB Headphones">%2$s</xliff:g>?\nThis app has not been granted record permission but could capture audio through this USB device.</string>
+
<!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
<string name="usb_accessory_confirm_prompt">Open <xliff:g id="application">%1$s</xliff:g> to handle <xliff:g id="usb_accessory">%2$s</xliff:g>?</string>
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 07bfa71..ff8a932 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.INotificationManager;
+import android.app.IWallpaperManager;
import android.content.res.Configuration;
import android.hardware.SensorPrivacyManager;
import android.hardware.display.NightDisplayListener;
@@ -77,6 +78,7 @@
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
@@ -318,6 +320,8 @@
@Inject Lazy<SysUiState> mSysUiStateFlagsContainer;
@Inject Lazy<AlarmManager> mAlarmManager;
@Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel;
+ @Inject Lazy<DozeParameters> mDozeParameters;
+ @Inject Lazy<IWallpaperManager> mWallpaperManager;
@Inject
public Dependency() {
@@ -504,6 +508,8 @@
mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get);
mProviders.put(AlarmManager.class, mAlarmManager::get);
mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get);
+ mProviders.put(DozeParameters.class, mDozeParameters::get);
+ mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
// TODO(b/118592525): to support multi-display , we start to add something which is
// per-display, while others may be global. I think it's time to add
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index cf199c5..9192eed 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -22,26 +22,36 @@
import static com.android.systemui.Dependency.MAIN_LOOPER_NAME;
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.app.AlarmManager;
+import android.app.IActivityManager;
import android.app.INotificationManager;
+import android.app.IWallpaperManager;
import android.content.Context;
+import android.content.res.Resources;
import android.hardware.SensorPrivacyManager;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.NightDisplayListener;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.view.IWindowManager;
+import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.widget.LockPatternUtils;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.plugins.PluginInitializerImpl;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
@@ -59,7 +69,11 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.util.leak.LeakDetector;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
import javax.inject.Named;
+import javax.inject.Qualifier;
import javax.inject.Singleton;
import dagger.Module;
@@ -71,6 +85,12 @@
*/
@Module
public class DependencyProvider {
+ @Qualifier
+ @Documented
+ @Retention(RUNTIME)
+ public @interface MainResources {
+ // TODO: use attribute to get other, non-main resources?
+ }
@Singleton
@Provides
@@ -249,4 +269,48 @@
public LockPatternUtils provideLockPatternUtils(Context context) {
return new LockPatternUtils(context);
}
+
+ /** */
+ @Provides
+ public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
+ return new AmbientDisplayConfiguration(context);
+ }
+
+ /** */
+ @Provides
+ public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
+ return new AlwaysOnDisplayPolicy(context);
+ }
+
+ /** */
+ @Provides
+ public PowerManager providePowerManager(Context context) {
+ return context.getSystemService(PowerManager.class);
+ }
+
+ /** */
+ @Provides
+ @MainResources
+ public Resources provideResources(Context context) {
+ return context.getResources();
+ }
+
+ /** */
+ @Provides
+ public IWallpaperManager provideWallPaperManager() {
+ return IWallpaperManager.Stub.asInterface(
+ ServiceManager.getService(Context.WALLPAPER_SERVICE));
+ }
+
+ /** */
+ @Provides
+ public WindowManager providesWindowManager(Context context) {
+ return context.getSystemService(WindowManager.class);
+ }
+
+ /** */
+ @Provides
+ public IActivityManager providesIActivityManager() {
+ return ActivityManager.getService();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 1c0e0b3..29a7167 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -38,6 +38,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
/**
* Default built-in wallpaper that simply shows a static image.
*/
@@ -50,8 +52,15 @@
private static final int INTERVAL_WAIT_FOR_RENDERING = 100;
private static final int PATIENCE_WAIT_FOR_RENDERING = 10;
private static final boolean DEBUG = true;
+ private final DozeParameters mDozeParameters;
private HandlerThread mWorker;
+ @Inject
+ public ImageWallpaper(DozeParameters dozeParameters) {
+ super();
+ mDozeParameters = dozeParameters;
+ }
+
@Override
public void onCreate() {
super.onCreate();
@@ -61,7 +70,7 @@
@Override
public Engine onCreateEngine() {
- return new GLEngine(this);
+ return new GLEngine(this, mDozeParameters);
}
@Override
@@ -89,9 +98,9 @@
// This variable can only be accessed in synchronized block.
private boolean mWaitingForRendering;
- GLEngine(Context context) {
+ GLEngine(Context context, DozeParameters dozeParameters) {
mNeedTransition = ActivityManager.isHighEndGfx()
- && !DozeParameters.getInstance(context).getDisplayNeedsBlanking();
+ && !dozeParameters.getDisplayNeedsBlanking();
// We will preserve EGL context when we are in lock screen or aod
// to avoid janking in following transition, we need to release when back to home.
@@ -339,9 +348,9 @@
boolean isHighEndGfx = ActivityManager.isHighEndGfx();
out.print(prefix); out.print("isHighEndGfx="); out.println(isHighEndGfx);
- DozeParameters dozeParameters = DozeParameters.getInstance(getApplicationContext());
out.print(prefix); out.print("displayNeedsBlanking=");
- out.println(dozeParameters != null ? dozeParameters.getDisplayNeedsBlanking() : "null");
+ out.println(
+ mDozeParameters != null ? mDozeParameters.getDisplayNeedsBlanking() : "null");
out.print(prefix); out.print("mNeedTransition="); out.println(mNeedTransition);
out.print(prefix); out.print("StatusBarState=");
diff --git a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
index e61268e..c11236e 100644
--- a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
@@ -40,6 +40,12 @@
/** */
@Binds
@IntoMap
+ @ClassKey(ImageWallpaper.class)
+ public abstract Service bindImageWallpaper(ImageWallpaper service);
+
+ /** */
+ @Binds
+ @IntoMap
@ClassKey(KeyguardService.class)
public abstract Service bindKeyguardService(KeyguardService service);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 189e511..91776a3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -237,7 +237,7 @@
if (statusBar != null) {
plugin.setup(statusBar.getStatusBarWindow(),
statusBar.getNavigationBarView(), new Callback(plugin),
- DozeParameters.getInstance(getBaseContext()));
+ Dependency.get(DozeParameters.class));
}
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index da4f304..ef7526b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -160,7 +160,8 @@
StatusBarStateController statusBarStateController) {
return new NotificationIconAreaController(context, statusBar, statusBarStateController,
wakeUpCoordinator, keyguardBypassController,
- Dependency.get(NotificationMediaManager.class));
+ Dependency.get(NotificationMediaManager.class),
+ Dependency.get(DozeParameters.class));
}
public KeyguardIndicationController createKeyguardIndicationController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index b069ba3..3f0505f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -18,6 +18,7 @@
import android.app.AlarmManager;
import android.app.Application;
+import android.app.IWallpaperManager;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
@@ -25,7 +26,6 @@
import android.os.Handler;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.dock.DockManager;
@@ -39,47 +39,71 @@
import com.android.systemui.util.wakelock.DelayedWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
+import javax.inject.Inject;
+
public class DozeFactory {
- public DozeFactory() {
+ private final FalsingManager mFalsingManager;
+ private final DozeLog mDozeLog;
+ private final DozeParameters mDozeParameters;
+ private final BatteryController mBatteryController;
+ private final AsyncSensorManager mAsyncSensorManager;
+ private final AlarmManager mAlarmManager;
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DockManager mDockManager;
+ private final IWallpaperManager mWallpaperManager;
+
+ @Inject
+ public DozeFactory(FalsingManager falsingManager, DozeLog dozeLog,
+ DozeParameters dozeParameters, BatteryController batteryController,
+ AsyncSensorManager asyncSensorManager, AlarmManager alarmManager,
+ WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ DockManager dockManager, IWallpaperManager wallpaperManager) {
+ mFalsingManager = falsingManager;
+ mDozeLog = dozeLog;
+ mDozeParameters = dozeParameters;
+ mBatteryController = batteryController;
+ mAsyncSensorManager = asyncSensorManager;
+ mAlarmManager = alarmManager;
+ mWakefulnessLifecycle = wakefulnessLifecycle;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mDockManager = dockManager;
+ mWallpaperManager = wallpaperManager;
}
/** Creates a DozeMachine with its parts for {@code dozeService}. */
- public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager,
- DozeLog dozeLog) {
- Context context = dozeService;
- AsyncSensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
- AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
- DockManager dockManager = Dependency.get(DockManager.class);
- WakefulnessLifecycle wakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
-
+ public DozeMachine assembleMachine(DozeService dozeService) {
DozeHost host = getHost(dozeService);
- AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(context);
- DozeParameters params = DozeParameters.getInstance(context);
+ AmbientDisplayConfiguration config = new AmbientDisplayConfiguration(dozeService);
Handler handler = new Handler();
WakeLock wakeLock = new DelayedWakeLock(handler,
- WakeLock.createPartial(context, "Doze"));
+ WakeLock.createPartial(dozeService, "Doze"));
DozeMachine.Service wrappedService = dozeService;
wrappedService = new DozeBrightnessHostForwarder(wrappedService, host);
- wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(wrappedService, params);
- wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(wrappedService,
- params);
+ wrappedService = DozeScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, mDozeParameters);
+ wrappedService = DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(
+ wrappedService, mDozeParameters);
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
- wakefulnessLifecycle, Dependency.get(BatteryController.class), dozeLog);
+ mWakefulnessLifecycle, mBatteryController, mDozeLog);
machine.setParts(new DozeMachine.Part[]{
- new DozePauser(handler, machine, alarmManager, params.getPolicy()),
- new DozeFalsingManagerAdapter(falsingManager),
- createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
- handler, wakeLock, machine, dockManager, dozeLog),
- createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params,
- dozeLog),
- new DozeScreenState(wrappedService, handler, host, params, wakeLock),
- createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
- handler),
- new DozeWallpaperState(context, getBiometricUnlockController(dozeService)),
- new DozeDockHandler(context, machine, host, config, handler, dockManager),
+ new DozePauser(handler, machine, mAlarmManager, mDozeParameters.getPolicy()),
+ new DozeFalsingManagerAdapter(mFalsingManager),
+ createDozeTriggers(dozeService, mAsyncSensorManager, host, mAlarmManager, config,
+ mDozeParameters, handler, wakeLock, machine, mDockManager, mDozeLog),
+ createDozeUi(dozeService, host, wakeLock, machine, handler, mAlarmManager,
+ mDozeParameters, mDozeLog),
+ new DozeScreenState(wrappedService, handler, host, mDozeParameters, wakeLock),
+ createDozeScreenBrightness(dozeService, wrappedService, mAsyncSensorManager, host,
+ mDozeParameters, handler),
+ new DozeWallpaperState(
+ mWallpaperManager,
+ getBiometricUnlockController(dozeService),
+ mDozeParameters),
+ new DozeDockHandler(dozeService, machine, host, config, handler, mDockManager),
new DozeAuthRemover(dozeService)
});
@@ -110,7 +134,7 @@
DozeMachine machine, Handler handler, AlarmManager alarmManager,
DozeParameters params, DozeLog dozeLog) {
return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params,
- Dependency.get(KeyguardUpdateMonitor.class), dozeLog);
+ mKeyguardUpdateMonitor, dozeLog);
}
public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 17559c9..08734d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -22,10 +22,8 @@
import android.service.dreams.DreamService;
import android.util.Log;
-import com.android.systemui.Dependency;
import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
-import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
@@ -38,18 +36,17 @@
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final FalsingManager mFalsingManager;
- private final DozeLog mDozeLog;
+ private final DozeFactory mDozeFactory;
private DozeMachine mDozeMachine;
private DozeServicePlugin mDozePlugin;
private PluginManager mPluginManager;
@Inject
- public DozeService(FalsingManager falsingManager, DozeLog dozeLog) {
+ public DozeService(DozeFactory dozeFactory, PluginManager pluginManager) {
setDebug(DEBUG);
- mFalsingManager = falsingManager;
- mDozeLog = dozeLog;
+ mDozeFactory = dozeFactory;
+ mPluginManager = pluginManager;
}
@Override
@@ -62,9 +59,8 @@
finish();
return;
}
- mPluginManager = Dependency.get(PluginManager.class);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager, mDozeLog);
+ mDozeMachine = mDozeFactory.assembleMachine(this);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 35c8b74..9457dc9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -17,12 +17,9 @@
package com.android.systemui.doze;
import android.app.IWallpaperManager;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -42,17 +39,10 @@
private final BiometricUnlockController mBiometricUnlockController;
private boolean mIsAmbientMode;
- public DozeWallpaperState(Context context,
- BiometricUnlockController biometricUnlockController) {
- this(IWallpaperManager.Stub.asInterface(
- ServiceManager.getService(Context.WALLPAPER_SERVICE)),
- biometricUnlockController,
- DozeParameters.getInstance(context));
- }
-
- @VisibleForTesting
- DozeWallpaperState(IWallpaperManager wallpaperManagerService,
- BiometricUnlockController biometricUnlockController, DozeParameters parameters) {
+ public DozeWallpaperState(
+ IWallpaperManager wallpaperManagerService,
+ BiometricUnlockController biometricUnlockController,
+ DozeParameters parameters) {
mWallpaperManagerService = wallpaperManagerService;
mBiometricUnlockController = biometricUnlockController;
mDozeParameters = parameters;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index daaee4c..1c8e451 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -16,6 +16,7 @@
import android.content.Context;
import android.os.Build;
+import android.provider.Settings;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -32,6 +33,7 @@
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
+import com.android.systemui.qs.tiles.ControlsTile;
import com.android.systemui.qs.tiles.DataSaverTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
@@ -58,6 +60,7 @@
private final Provider<WifiTile> mWifiTileProvider;
private final Provider<BluetoothTile> mBluetoothTileProvider;
+ private final Provider<ControlsTile> mControlsTileProvider;
private final Provider<CellularTile> mCellularTileProvider;
private final Provider<DndTile> mDndTileProvider;
private final Provider<ColorInversionTile> mColorInversionTileProvider;
@@ -81,6 +84,7 @@
@Inject
public QSFactoryImpl(Provider<WifiTile> wifiTileProvider,
Provider<BluetoothTile> bluetoothTileProvider,
+ Provider<ControlsTile> controlsTileProvider,
Provider<CellularTile> cellularTileProvider,
Provider<DndTile> dndTileProvider,
Provider<ColorInversionTile> colorInversionTileProvider,
@@ -100,6 +104,7 @@
Provider<UiModeNightTile> uiModeNightTileProvider) {
mWifiTileProvider = wifiTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
+ mControlsTileProvider = controlsTileProvider;
mCellularTileProvider = cellularTileProvider;
mDndTileProvider = dndTileProvider;
mColorInversionTileProvider = colorInversionTileProvider;
@@ -138,6 +143,11 @@
return mWifiTileProvider.get();
case "bt":
return mBluetoothTileProvider.get();
+ case "controls":
+ if (Settings.System.getInt(mHost.getContext().getContentResolver(),
+ "qs_controls_tile_enabled", 0) == 1) {
+ return mControlsTileProvider.get();
+ } else return null;
case "cell":
return mCellularTileProvider.get();
case "dnd":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
new file mode 100644
index 0000000..0a59618
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ControlsTile.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.HomeControlsPlugin;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.shared.plugins.PluginManager;
+
+import javax.inject.Inject;
+
+
+/**
+ * Temporary control test for prototyping
+ */
+public class ControlsTile extends QSTileImpl<BooleanState> {
+ private ControlsDetailAdapter mDetailAdapter;
+ private final ActivityStarter mActivityStarter;
+ private PluginManager mPluginManager;
+ private HomeControlsPlugin mPlugin;
+ private Intent mHomeAppIntent;
+
+ @Inject
+ public ControlsTile(QSHost host,
+ ActivityStarter activityStarter,
+ PluginManager pluginManager) {
+ super(host);
+ mActivityStarter = activityStarter;
+ mPluginManager = pluginManager;
+ mDetailAdapter = (ControlsDetailAdapter) createDetailAdapter();
+
+ mHomeAppIntent = new Intent(Intent.ACTION_VIEW);
+ mHomeAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mHomeAppIntent.setComponent(new ComponentName("com.google.android.apps.chromecast.app",
+ "com.google.android.apps.chromecast.app.DiscoveryActivity"));
+ }
+
+ @Override
+ public DetailAdapter getDetailAdapter() {
+ return mDetailAdapter;
+ }
+
+ @Override
+ public BooleanState newTileState() {
+ return new BooleanState();
+ }
+
+ @Override
+ public void handleSetListening(boolean listening) {
+
+ }
+
+ @Override
+ public void setDetailListening(boolean listening) {
+ if (mPlugin == null) return;
+
+ mPlugin.setVisible(listening);
+ }
+
+ @Override
+ protected void handleClick() {
+ showDetail(true);
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return mHomeAppIntent;
+ }
+
+ @Override
+ protected void handleSecondaryClick() {
+ showDetail(true);
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return "Controls";
+ }
+
+ @Override
+ protected void handleUpdateState(BooleanState state, Object arg) {
+ state.icon = ResourceIcon.get(R.drawable.ic_lightbulb_outline_gm2_24px);
+ state.label = "Controls";
+ }
+
+ @Override
+ public boolean supportsDetailView() {
+ return getDetailAdapter() != null && mQSSettingsPanelOption == QSSettingsPanel.OPEN_CLICK;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return -1;
+ }
+
+ @Override
+ protected String composeChangeAnnouncement() {
+ if (mState.value) {
+ return "On";
+ } else {
+ return "Off";
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ protected DetailAdapter createDetailAdapter() {
+ mDetailAdapter = new ControlsDetailAdapter();
+ return mDetailAdapter;
+ }
+
+ private class ControlsDetailAdapter implements DetailAdapter {
+ private View mDetailView;
+ protected LinearLayout mHomeControlsLayout;
+
+ public CharSequence getTitle() {
+ return "Controls";
+ }
+
+ public Boolean getToggleState() {
+ return null;
+ }
+
+ public boolean getToggleEnabled() {
+ return false;
+ }
+
+ public View createDetailView(Context context, View convertView, final ViewGroup parent) {
+ mHomeControlsLayout = (LinearLayout) LayoutInflater.from(context).inflate(
+ R.layout.home_controls, parent, false);
+ mHomeControlsLayout.setVisibility(View.VISIBLE);
+ mPluginManager.addPluginListener(
+ new PluginListener<HomeControlsPlugin>() {
+ @Override
+ public void onPluginConnected(HomeControlsPlugin plugin,
+ Context pluginContext) {
+ mPlugin = plugin;
+ mPlugin.sendParentGroup(mHomeControlsLayout);
+ mPlugin.setVisible(true);
+ }
+
+ @Override
+ public void onPluginDisconnected(HomeControlsPlugin plugin) {
+
+ }
+ }, HomeControlsPlugin.class, false);
+ return mHomeControlsLayout;
+ }
+
+ public Intent getSettingsIntent() {
+ return mHomeAppIntent;
+ }
+
+ public void setToggleState(boolean state) {
+
+ }
+
+ public int getMetricsCategory() {
+ return -1;
+ }
+
+ public boolean hasHeader() {
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 2f67f90..8a23e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -37,10 +37,10 @@
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
- private val mContext: Context,
private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
private val statusBarStateController: StatusBarStateController,
- private val bypassController: KeyguardBypassController)
+ private val bypassController: KeyguardBypassController,
+ private val dozeParameters: DozeParameters)
: OnHeadsUpChangedListener, StatusBarStateController.StateListener,
PanelExpansionListener {
@@ -67,7 +67,6 @@
private var mVisibilityAmount = 0.0f
private var mLinearVisibilityAmount = 0.0f
private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
- private val mDozeParameters: DozeParameters
private var pulseExpanding: Boolean = false
private val wakeUpListeners = arrayListOf<WakeUpListener>()
private var state: Int = StatusBarState.KEYGUARD
@@ -146,7 +145,6 @@
init {
mHeadsUpManagerPhone.addListener(this)
statusBarStateController.addCallback(this)
- mDozeParameters = DozeParameters.getInstance(mContext)
addListener(object : WakeUpListener {
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
if (isFullyHidden && mNotificationsVisibleForExpansion) {
@@ -377,7 +375,7 @@
}
private fun shouldAnimateVisibility() =
- mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking()
+ dozeParameters.getAlwaysOn() && !dozeParameters.getDisplayNeedsBlanking()
interface WakeUpListener {
/**
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 7cbdfb0..548afd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -128,6 +128,7 @@
private final KeyguardBypassController mKeyguardBypassController;
private PowerManager.WakeLock mWakeLock;
private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final DozeParameters mDozeParameters;
private final KeyguardStateController mKeyguardStateController;
private final StatusBarWindowController mStatusBarWindowController;
private final Context mContext;
@@ -146,31 +147,33 @@
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
- public BiometricUnlockController(Context context,
+ public BiometricUnlockController(
+ Context context,
DozeScrimController dozeScrimController,
KeyguardViewMediator keyguardViewMediator,
ScrimController scrimController,
StatusBar statusBar,
KeyguardStateController keyguardStateController, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController,
+ DozeParameters dozeParameters) {
this(context, dozeScrimController, keyguardViewMediator, scrimController, statusBar,
keyguardStateController, handler, keyguardUpdateMonitor,
context.getResources()
.getInteger(com.android.internal.R.integer.config_wakeUpDelayDoze),
- keyguardBypassController);
+ keyguardBypassController, dozeParameters);
}
@VisibleForTesting
- protected BiometricUnlockController(Context context,
- DozeScrimController dozeScrimController, KeyguardViewMediator keyguardViewMediator,
- ScrimController scrimController, StatusBar statusBar,
- KeyguardStateController keyguardStateController, Handler handler,
+ protected BiometricUnlockController(Context context, DozeScrimController dozeScrimController,
+ KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
+ StatusBar statusBar, KeyguardStateController keyguardStateController, Handler handler,
KeyguardUpdateMonitor keyguardUpdateMonitor, int wakeUpDelay,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController, DozeParameters dozeParameters) {
mContext = context;
mPowerManager = context.getSystemService(PowerManager.class);
mUpdateMonitor = keyguardUpdateMonitor;
+ mDozeParameters = dozeParameters;
mUpdateMonitor.registerCallback(this);
mMediaManager = Dependency.get(NotificationMediaManager.class);
Dependency.get(WakefulnessLifecycle.class).addObserver(mWakefulnessObserver);
@@ -284,7 +287,7 @@
}
// 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 alwaysOnEnabled = mDozeParameters.getAlwaysOn();
boolean delayWakeUp = mode == MODE_WAKE_AND_UNLOCK && alwaysOnEnabled && mWakeUpDelay > 0;
Runnable wakeUp = ()-> {
if (!wasDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index bb6a38e..28dac87 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -16,7 +16,7 @@
package com.android.systemui.statusbar.phone;
-import android.content.Context;
+import android.content.res.Resources;
import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
import android.os.SystemProperties;
@@ -25,7 +25,7 @@
import android.util.MathUtils;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
+import com.android.systemui.DependencyProvider;
import com.android.systemui.R;
import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
@@ -33,9 +33,13 @@
import java.io.PrintWriter;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
/**
* Retrieve doze information
*/
+@Singleton
public class DozeParameters implements TunerService.Tunable,
com.android.systemui.plugins.statusbar.DozeParameters {
private static final int MAX_DURATION = 60 * 1000;
@@ -44,35 +48,33 @@
public static final boolean FORCE_BLANKING =
SystemProperties.getBoolean("debug.force_blanking", false);
- private static DozeParameters sInstance;
-
- private final Context mContext;
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final PowerManager mPowerManager;
private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
+ private final Resources mResources;
private boolean mDozeAlwaysOn;
private boolean mControlScreenOffAnimation;
- public static DozeParameters getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new DozeParameters(context);
- }
- return sInstance;
- }
-
- @VisibleForTesting
- protected DozeParameters(Context context) {
- mContext = context.getApplicationContext();
- mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
- mAlwaysOnPolicy = new AlwaysOnDisplayPolicy(mContext);
+ @Inject
+ protected DozeParameters(
+ @DependencyProvider.MainResources Resources resources,
+ AmbientDisplayConfiguration ambientDisplayConfiguration,
+ AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
+ PowerManager powerManager,
+ TunerService tunerService) {
+ mResources = resources;
+ mAmbientDisplayConfiguration = ambientDisplayConfiguration;
+ mAlwaysOnPolicy = alwaysOnDisplayPolicy;
mControlScreenOffAnimation = !getDisplayNeedsBlanking();
- mPowerManager = mContext.getSystemService(PowerManager.class);
+ mPowerManager = powerManager;
mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
- Dependency.get(TunerService.class).addTunable(this, Settings.Secure.DOZE_ALWAYS_ON,
+ tunerService.addTunable(
+ this,
+ Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
}
@@ -95,7 +97,7 @@
}
public boolean getDozeSuspendDisplayStateSupported() {
- return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
+ return mResources.getBoolean(R.bool.doze_suspend_display_state_supported);
}
public int getPulseDuration() {
@@ -103,7 +105,7 @@
}
public float getScreenBrightnessDoze() {
- return mContext.getResources().getInteger(
+ return mResources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
}
@@ -173,7 +175,7 @@
* @return {@code true} if screen needs to be completely black before a power transition.
*/
public boolean getDisplayNeedsBlanking() {
- return FORCE_BLANKING || !FORCE_NO_BLANKING && mContext.getResources().getBoolean(
+ return FORCE_BLANKING || !FORCE_NO_BLANKING && mResources.getBoolean(
com.android.internal.R.bool.config_displayBlanksAfterDoze);
}
@@ -195,24 +197,20 @@
}
private boolean getBoolean(String propName, int resId) {
- return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
+ return SystemProperties.getBoolean(propName, mResources.getBoolean(resId));
}
private int getInt(String propName, int resId) {
- int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
+ int value = SystemProperties.getInt(propName, mResources.getInteger(resId));
return MathUtils.constrain(value, 0, MAX_DURATION);
}
- private String getString(String propName, int resId) {
- return SystemProperties.get(propName, mContext.getString(resId));
- }
-
public int getPulseVisibleDurationExtended() {
return 2 * getPulseVisibleDuration();
}
public boolean doubleTapReportsTouchCoordinates() {
- return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
+ return mResources.getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1a3560e..1a37520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -80,11 +80,14 @@
private boolean mAodIconsVisible;
private boolean mIsPulsing;
- public NotificationIconAreaController(Context context, StatusBar statusBar,
+ public NotificationIconAreaController(
+ Context context,
+ StatusBar statusBar,
StatusBarStateController statusBarStateController,
NotificationWakeUpCoordinator wakeUpCoordinator,
KeyguardBypassController keyguardBypassController,
- NotificationMediaManager notificationMediaManager) {
+ NotificationMediaManager notificationMediaManager,
+ DozeParameters dozeParameters) {
mStatusBar = statusBar;
mContrastColorUtil = ContrastColorUtil.getInstance(context);
mContext = context;
@@ -92,7 +95,7 @@
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
mMediaManager = notificationMediaManager;
- mDozeParameters = DozeParameters.getInstance(mContext);
+ mDozeParameters = dozeParameters;
mWakeUpCoordinator = wakeUpCoordinator;
wakeUpCoordinator.addListener(this);
mBypassController = keyguardBypassController;
@@ -533,8 +536,7 @@
}
public void appearAodIcons() {
- DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
- if (dozeParameters.shouldControlScreenOff()) {
+ if (mDozeParameters.shouldControlScreenOff()) {
mAodIcons.setTranslationY(-mAodIconAppearTranslation);
mAodIcons.setAlpha(0);
animateInAodIconTranslation();
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 9ab635c..89051cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -146,6 +146,7 @@
* Fling until QS is completely hidden.
*/
public static final int FLING_HIDE = 2;
+ private final DozeParameters mDozeParameters;
private double mQqsSplitFraction;
@@ -454,18 +455,15 @@
@Inject
public NotificationPanelView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
InjectionInflationController injectionInflationController,
- NotificationWakeUpCoordinator coordinator,
- PulseExpansionHandler pulseExpansionHandler,
+ NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
- KeyguardBypassController bypassController,
- FalsingManager falsingManager,
- PluginManager pluginManager,
- ShadeController shadeController,
+ KeyguardBypassController bypassController, FalsingManager falsingManager,
+ PluginManager pluginManager, ShadeController shadeController,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
- StatusBarStateController statusBarStateController,
- DozeLog dozeLog) {
+ StatusBarStateController statusBarStateController, DozeLog dozeLog,
+ DozeParameters dozeParameters) {
super(context, attrs, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController);
setWillNotDraw(!DEBUG);
@@ -480,6 +478,7 @@
mCommandQueue = getComponent(context, CommandQueue.class);
mDisplayId = context.getDisplayId();
mPulseExpansionHandler = pulseExpansionHandler;
+ mDozeParameters = dozeParameters;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -3435,9 +3434,8 @@
public void setPulsing(boolean pulsing) {
mPulsing = pulsing;
- DozeParameters dozeParameters = DozeParameters.getInstance(mContext);
- final boolean animatePulse = !dozeParameters.getDisplayNeedsBlanking()
- && dozeParameters.getAlwaysOn();
+ final boolean animatePulse = !mDozeParameters.getDisplayNeedsBlanking()
+ && mDozeParameters.getAlwaysOn();
if (animatePulse) {
mAnimateNextPositionUpdate = true;
}
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 d1fe46e..c092f9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -387,6 +387,7 @@
private final ConfigurationController mConfigurationController;
private final StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
private final NotifLog mNotifLog;
+ private final DozeParameters mDozeParameters;
// expanded notifications
protected NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -497,8 +498,7 @@
WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT);
final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_dozeSupportsAodWallpaper);
- final boolean imageWallpaperInAmbient =
- !DozeParameters.getInstance(mContext).getDisplayNeedsBlanking();
+ final boolean imageWallpaperInAmbient = !mDozeParameters.getDisplayNeedsBlanking();
// If WallpaperInfo is null, it must be ImageWallpaper.
final boolean supportsAmbientMode = deviceSupportsAodWallpaper
&& ((info == null && imageWallpaperInAmbient)
@@ -674,7 +674,8 @@
ConfigurationController configurationController,
StatusBarWindowController statusBarWindowController,
StatusBarWindowViewController.Builder statusBarWindowViewControllerBuilder,
- NotifLog notifLog) {
+ NotifLog notifLog,
+ DozeParameters dozeParameters) {
super(context);
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
@@ -730,6 +731,7 @@
mStatusBarWindowController = statusBarWindowController;
mStatusBarWindowViewControllerBuilder = statusBarWindowViewControllerBuilder;
mNotifLog = notifLog;
+ mDozeParameters = dozeParameters;
mBubbleExpandListener =
(isExpanding, key) -> {
@@ -750,7 +752,7 @@
KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
if (sliceProvider != null) {
sliceProvider.initDependencies(mMediaManager, mStatusBarStateController,
- mKeyguardBypassController, DozeParameters.getInstance(mContext));
+ mKeyguardBypassController, mDozeParameters);
} else {
Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
}
@@ -1032,13 +1034,12 @@
if (mStatusBarWindow != null) {
mStatusBarWindowViewController.onScrimVisibilityChanged(scrimsVisible);
}
- }, DozeParameters.getInstance(mContext),
+ }, mDozeParameters,
mContext.getSystemService(AlarmManager.class),
mKeyguardStateController);
mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
mHeadsUpManager, mNotificationIconAreaController, mScrimController);
- mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context),
- mDozeLog);
+ mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog);
BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop);
mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
@@ -1343,7 +1344,7 @@
mBiometricUnlockController = new BiometricUnlockController(mContext,
mDozeScrimController, mKeyguardViewMediator,
mScrimController, this, mKeyguardStateController, new Handler(),
- mKeyguardUpdateMonitor, mKeyguardBypassController);
+ mKeyguardUpdateMonitor, mKeyguardBypassController, mDozeParameters);
putComponent(BiometricUnlockController.class, mBiometricUnlockController);
mStatusBarKeyguardViewManager = mKeyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
@@ -3571,8 +3572,7 @@
mDozing = isDozing;
// Collapse the notification panel if open
- boolean dozingAnimated = mDozingRequested
- && DozeParameters.getInstance(mContext).shouldControlScreenOff();
+ boolean dozingAnimated = mDozingRequested && mDozeParameters.shouldControlScreenOff();
mNotificationPanel.resetViews(dozingAnimated);
updateQsExpansionEnabled();
@@ -3828,7 +3828,7 @@
*/
private void updateNotificationPanelTouchState() {
boolean goingToSleepWithoutAnimation = isGoingToSleep()
- && !DozeParameters.getInstance(mContext).shouldControlScreenOff();
+ && !mDozeParameters.shouldControlScreenOff();
boolean disabled = (!mDeviceInteractive && !mPulsing) || goingToSleepWithoutAnimation;
mNotificationPanel.setTouchAndAnimationDisabled(disabled);
mNotificationIconAreaController.setAnimationsEnabled(!disabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 724b462..ca7a936 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -21,7 +21,6 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
-import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -39,8 +38,6 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -94,24 +91,14 @@
private final ArrayList<WeakReference<StatusBarWindowCallback>>
mCallbacks = Lists.newArrayList();
- private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+ private final SysuiColorExtractor mColorExtractor;
@Inject
- public StatusBarWindowController(Context context,
- StatusBarStateController statusBarStateController,
- ConfigurationController configurationController,
- KeyguardBypassController keyguardBypassController) {
- this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
- DozeParameters.getInstance(context), statusBarStateController,
- configurationController, keyguardBypassController);
- }
-
- @VisibleForTesting
public StatusBarWindowController(Context context, WindowManager windowManager,
IActivityManager activityManager, DozeParameters dozeParameters,
StatusBarStateController statusBarStateController,
ConfigurationController configurationController,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor) {
mContext = context;
mWindowManager = windowManager;
mActivityManager = activityManager;
@@ -120,6 +107,7 @@
mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
mLpChanged = new LayoutParams();
mKeyguardBypassController = keyguardBypassController;
+ mColorExtractor = colorExtractor;
mLockScreenDisplayTimeout = context.getResources()
.getInteger(R.integer.config_lockScreenDisplayTimeout);
((SysuiStatusBarStateController) statusBarStateController)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
index 1ce7763..fd3f9c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowViewController.java
@@ -93,7 +93,8 @@
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController,
- DozeLog dozeLog) {
+ DozeLog dozeLog,
+ DozeParameters dozeParameters) {
mView = view;
mFalsingManager = falsingManager;
@@ -113,7 +114,8 @@
notificationEntryManager,
keyguardStateController,
statusBarStateController,
- dozeLog);
+ dozeLog,
+ dozeParameters);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
notificationPanelView.setVisibility(View.INVISIBLE);
@@ -485,6 +487,7 @@
private final NotificationLockscreenUserManager mNotificationLockScreenUserManager;
private final NotificationEntryManager mNotificationEntryManager;
private final DozeLog mDozeLog;
+ private final DozeParameters mDozeParameters;
private StatusBarWindowView mView;
@Inject
@@ -501,7 +504,8 @@
NotificationEntryManager notificationEntryManager,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
- DozeLog dozeLog) {
+ DozeLog dozeLog,
+ DozeParameters dozeParameters) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -515,6 +519,7 @@
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
mDozeLog = dozeLog;
+ mDozeParameters = dozeParameters;
}
/**
@@ -552,7 +557,8 @@
mNotificationEntryManager,
mKeyguardStateController,
mStatusBarStateController,
- mDozeLog);
+ mDozeLog,
+ mDozeParameters);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
new file mode 100644
index 0000000..a601e9b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/OWNERS
@@ -0,0 +1,8 @@
+# Android TV Core Framework
+rgl@google.com
+valiiftime@google.com
+galinap@google.com
+patrikf@google.com
+robhor@google.com
+sergeynv@google.com
+
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index 0a3e34e..fd99ef3 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.PermissionChecker;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.hardware.usb.IUsbManager;
@@ -63,6 +64,7 @@
mDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
mResolveInfo = (ResolveInfo) intent.getParcelableExtra("rinfo");
+ String packageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
PackageManager packageManager = getPackageManager();
String appName = mResolveInfo.loadLabel(packageManager).toString();
@@ -74,8 +76,20 @@
mAccessory.getDescription());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
} else {
- ap.mMessage = getString(R.string.usb_device_confirm_prompt, appName,
- mDevice.getProductName());
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ boolean hasRecordPermission =
+ PermissionChecker.checkPermissionForPreflight(
+ this, android.Manifest.permission.RECORD_AUDIO, -1, uid,
+ packageName)
+ == android.content.pm.PackageManager.PERMISSION_GRANTED;
+ boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
+ boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
+
+ int strID = useRecordWarning
+ ? R.string.usb_device_confirm_prompt_warn
+ : R.string.usb_device_confirm_prompt;
+
+ ap.mMessage = getString(strID, appName, mDevice.getProductName());
mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
}
ap.mPositiveButtonText = getString(android.R.string.ok);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index dd5211d..3472573 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -56,8 +56,10 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -141,6 +143,10 @@
private BubbleController.BubbleExpandListener mBubbleExpandListener;
@Mock
private PendingIntent mDeleteIntent;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ ColorExtractor.GradientColors mGradientColors;
private BubbleData mBubbleData;
@@ -150,11 +156,12 @@
mStatusBarView = new FrameLayout(mContext);
mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
mContext.addMockSystemService(FaceManager.class, mFaceManager);
+ when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
// Bubbles get added to status bar window view
mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
mActivityManager, mDozeParameters, mStatusBarStateController,
- mConfigurationController, mKeyguardBypassController);
+ mConfigurationController, mKeyguardBypassController, mColorExtractor);
mStatusBarWindowController.add(mStatusBarView, 120 /* height */);
// Need notifications for bubbles
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index ff9aae7..72bea56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -76,6 +76,8 @@
private Handler mHandler;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private DozeParameters mDozeParameters;
private BiometricUnlockController mBiometricUnlockController;
@Before
@@ -92,7 +94,8 @@
mStatusBarWindowController);
mBiometricUnlockController = new BiometricUnlockController(mContext, mDozeScrimController,
mKeyguardViewMediator, mScrimController, mStatusBar, mKeyguardStateController,
- mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController);
+ mHandler, mUpdateMonitor, 0 /* wakeUpDelay */, mKeyguardBypassController,
+ mDozeParameters);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
index 60050b1..debc840 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeParametersTest.java
@@ -17,68 +17,73 @@
package com.android.systemui.statusbar.phone;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
-import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.PowerManager;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.AlwaysOnDisplayPolicy;
import com.android.systemui.doze.DozeScreenState;
+import com.android.systemui.tuner.TunerService;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DozeParametersTest extends SysuiTestCase {
+ private DozeParameters mDozeParameters;
+
+ @Mock Resources mResources;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+ @Mock private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
+ @Mock private PowerManager mPowerManager;
+ @Mock private TunerService mTunerService;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mDozeParameters = new DozeParameters(
+ mResources,
+ mAmbientDisplayConfiguration,
+ mAlwaysOnDisplayPolicy,
+ mPowerManager,
+ mTunerService
+ );
+ }
@Test
public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_false() {
- TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
- PowerManager mockedPowerManager = dozeParameters.getPowerManager();
- dozeParameters.setControlScreenOffAnimation(true);
- reset(mockedPowerManager);
- dozeParameters.setControlScreenOffAnimation(false);
- verify(mockedPowerManager).setDozeAfterScreenOff(eq(true));
+ mDozeParameters.setControlScreenOffAnimation(true);
+ reset(mPowerManager);
+ mDozeParameters.setControlScreenOffAnimation(false);
+ verify(mPowerManager).setDozeAfterScreenOff(eq(true));
}
@Test
public void test_setControlScreenOffAnimation_setsDozeAfterScreenOff_true() {
- TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
- PowerManager mockedPowerManager = dozeParameters.getPowerManager();
- dozeParameters.setControlScreenOffAnimation(false);
- reset(mockedPowerManager);
- dozeParameters.setControlScreenOffAnimation(true);
- verify(dozeParameters.getPowerManager()).setDozeAfterScreenOff(eq(false));
+ mDozeParameters.setControlScreenOffAnimation(false);
+ reset(mPowerManager);
+ mDozeParameters.setControlScreenOffAnimation(true);
+ verify(mPowerManager).setDozeAfterScreenOff(eq(false));
}
@Test
public void test_getWallpaperAodDuration_when_shouldControlScreenOff() {
- TestableDozeParameters dozeParameters = new TestableDozeParameters(getContext());
- dozeParameters.setControlScreenOffAnimation(true);
- Assert.assertEquals("wallpaper hides faster when controlling screen off",
- dozeParameters.getWallpaperAodDuration(),
+ mDozeParameters.setControlScreenOffAnimation(true);
+ Assert.assertEquals(
+ "wallpaper hides faster when controlling screen off",
+ mDozeParameters.getWallpaperAodDuration(),
DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY);
}
-
- private class TestableDozeParameters extends DozeParameters {
- private PowerManager mPowerManager;
-
- TestableDozeParameters(Context context) {
- super(context);
- mPowerManager = mock(PowerManager.class);
- }
-
- @Override
- protected PowerManager getPowerManager() {
- return mPowerManager;
- }
- }
-
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2c19037..cff6635 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -116,6 +116,7 @@
private FalsingManager mFalsingManager;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock private DozeParameters mDozeParameters;
private NotificationPanelView mNotificationPanelView;
@Before
@@ -130,10 +131,11 @@
mDependency.injectMockDependency(ConfigurationController.class);
mDependency.injectMockDependency(ZenModeController.class);
NotificationWakeUpCoordinator coordinator =
- new NotificationWakeUpCoordinator(mContext,
+ new NotificationWakeUpCoordinator(
mock(HeadsUpManagerPhone.class),
new StatusBarStateControllerImpl(),
- mKeyguardBypassController);
+ mKeyguardBypassController,
+ mDozeParameters);
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
mContext,
coordinator,
@@ -239,7 +241,8 @@
mock(NotifLog.class)),
mock(KeyguardStateController.class),
statusBarStateController,
- mock(DozeLog.class));
+ mock(DozeLog.class),
+ mDozeParameters);
mNotificationStackScroller = mNotificationStackScrollLayout;
mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f76dc61..8f1b6017 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -220,6 +220,7 @@
@Mock private StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
@Mock private StatusBarWindowViewController mStatusBarWindowViewController;
@Mock private NotifLog mNotifLog;
+ @Mock private DozeParameters mDozeParameters;
@Before
public void setup() throws Exception {
@@ -343,7 +344,8 @@
configurationController,
mStatusBarWindowController,
mStatusBarWindowViewControllerBuilder,
- mNotifLog);
+ mNotifLog,
+ mDozeParameters);
// TODO: we should be able to call mStatusBar.start() and have all the below values
// initialized automatically.
mStatusBar.mComponents = mContext.getComponents();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
index 4ffaeae..a21a658 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowControllerTest.java
@@ -32,7 +32,9 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.colorextraction.ColorExtractor;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -48,20 +50,15 @@
@SmallTest
public class StatusBarWindowControllerTest extends SysuiTestCase {
- @Mock
- private WindowManager mWindowManager;
- @Mock
- private DozeParameters mDozeParameters;
- @Mock
- private ViewGroup mStatusBarView;
- @Mock
- private IActivityManager mActivityManager;
- @Mock
- private SysuiStatusBarStateController mStatusBarStateController;
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private KeyguardBypassController mKeyguardBypassController;
+ @Mock private WindowManager mWindowManager;
+ @Mock private DozeParameters mDozeParameters;
+ @Mock private ViewGroup mStatusBarView;
+ @Mock private IActivityManager mActivityManager;
+ @Mock private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock private ConfigurationController mConfigurationController;
+ @Mock private KeyguardBypassController mKeyguardBypassController;
+ @Mock private SysuiColorExtractor mColorExtractor;
+ @Mock ColorExtractor.GradientColors mGradientColors;
private StatusBarWindowController mStatusBarWindowController;
@@ -69,10 +66,11 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
mActivityManager, mDozeParameters, mStatusBarStateController,
- mConfigurationController, mKeyguardBypassController);
+ mConfigurationController, mKeyguardBypassController, mColorExtractor);
mStatusBarWindowController.add(mStatusBarView, 100 /* height */);
}
@@ -96,9 +94,6 @@
@Test
public void testOnThemeChanged_doesntCrash() {
- mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
- mActivityManager, mDozeParameters, mStatusBarStateController,
- mConfigurationController, mKeyguardBypassController);
mStatusBarWindowController.onThemeChanged();
}
@@ -109,9 +104,6 @@
@Test
public void testSetForcePluginOpen_beforeStatusBarInitialization() {
- mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
- mActivityManager, mDozeParameters, mStatusBarStateController,
- mConfigurationController, mKeyguardBypassController);
mStatusBarWindowController.setForcePluginOpen(true);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 0ef1acc..7c1dfa6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -70,6 +70,7 @@
@Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private StatusBar mStatusBar;
@Mock private DozeLog mDozeLog;
+ @Mock private DozeParameters mDozeParameters;
@Before
public void setUp() {
@@ -94,7 +95,8 @@
mNotificationEntryManager,
mKeyguardStateController,
mStatusBarStateController,
- mDozeLog)
+ mDozeLog,
+ mDozeParameters)
.setShadeController(mShadeController)
.setStatusBarWindowView(mView)
.build();
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index e5e11ea..ac006df 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -239,7 +239,6 @@
private final KeyValueBackupReporter mReporter;
private final OnTaskFinishedListener mTaskFinishedListener;
private final boolean mUserInitiated;
- private final boolean mNonIncremental;
private final int mCurrentOpToken;
private final int mUserId;
private final File mStateDirectory;
@@ -264,6 +263,7 @@
// and at least one of the packages had data. Used to avoid updating current token for
// empty backups.
private boolean mHasDataToBackup;
+ private boolean mNonIncremental;
/**
* This {@link ConditionVariable} is used to signal that the cancel operation has been
@@ -412,6 +412,11 @@
try {
IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.startTask()");
String transportName = transport.name();
+ if (transportName.contains("EncryptedLocalTransport")) {
+ // Temporary code for EiTF POC. Only supports non-incremental backups.
+ mNonIncremental = true;
+ }
+
mReporter.onTransportReady(transportName);
// If we haven't stored PM metadata yet, we must initialize the transport.
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 05b6168..c8179a7 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -131,7 +131,7 @@
private static class FeatureConfigImpl implements FeatureConfig {
private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled";
- private volatile boolean mFeatureEnabled = true;
+ private volatile boolean mFeatureEnabled = false;
private CompatConfig mCompatibility;
private FeatureConfigImpl(PackageManagerService.Injector injector) {
@@ -141,12 +141,12 @@
@Override
public void onSystemReady() {
mFeatureEnabled = DeviceConfig.getBoolean(
- NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, true);
+ NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, false);
DeviceConfig.addOnPropertiesChangedListener(
NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(),
properties -> {
synchronized (FeatureConfigImpl.this) {
- mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, true);
+ mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, false);
}
});
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3f45b0b..5c65752 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -297,7 +297,7 @@
// Critical; after this call the application should never have the permission
mPackageManagerInt.writeSettings(false);
final int appId = UserHandle.getAppId(uid);
- killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
+ mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED));
}
@Override
public void onInstallPermissionRevoked() {
@@ -1902,7 +1902,7 @@
private void restoreRuntimePermissions(@NonNull byte[] backup, @NonNull UserHandle user) {
synchronized (mLock) {
mHasNoDelayedPermBackup.delete(user.getIdentifier());
- mPermissionControllerManager.restoreRuntimePermissionBackup(backup, user);
+ mPermissionControllerManager.stageAndApplyRuntimePermissionsBackup(backup, user);
}
}
@@ -1923,7 +1923,7 @@
return;
}
- mPermissionControllerManager.restoreDelayedRuntimePermissionBackup(packageName, user,
+ mPermissionControllerManager.applyStagedRuntimePermissionBackup(packageName, user,
mContext.getMainExecutor(), (hasMoreBackup) -> {
if (hasMoreBackup) {
return;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 76a551f..fb4de01 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2005,10 +2005,6 @@
if (stopped) {
clearOptionsLocked();
}
-
- if (mAtmService != null) {
- mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
- }
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 7753f57..ca74196 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1796,6 +1796,7 @@
tr.removeTaskActivitiesLocked(reason);
cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
mService.getLockTaskController().clearLockedTask(tr);
+ mService.getTaskChangeNotificationController().notifyTaskStackChanged();
if (tr.isPersistable) {
mService.notifyTaskPersisterLocked(null, true);
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f0717ca..2657826 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -120,12 +120,12 @@
// TODO: Remove after unification.
@Override
- public void onConfigurationChanged(Configuration newParentConfig) {
+ public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
// Forward configuration changes in cases
// - children won't get it from TaskRecord
// - it's a pinned task
- onConfigurationChanged(newParentConfig,
- (mTaskRecord == null) || inPinnedWindowingMode() /*forwardToChildren*/);
+ forwardToChildren &= (mTaskRecord == null) || inPinnedWindowingMode();
+ super.onConfigurationChanged(newParentConfig, forwardToChildren);
}
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, int resizeMode,
diff --git a/tests/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
index 55a6147..f34c432 100644
--- a/tests/FlickerTests/TEST_MAPPING
+++ b/tests/FlickerTests/TEST_MAPPING
@@ -1,7 +1,8 @@
{
"postsubmit": [
{
- "name": "FlickerTests"
+ "name": "FlickerTests",
+ "keywords": ["primary-device"]
}
]
}
\ No newline at end of file